c语言宏定义#define的亮和资料整理

1. 运define来定义 数值宏常量

 

  #define
宏定义是个演技大巧妙的替身演员,但为会见时常打大牌的,所以我们因此其要慎之又慎。它可出现于代码的另外地方,从行业宏定义开始,以后的代码就不怕还认是宏了;也可以管另外事物定义成宏。因为编译器会以预编译的时候用肢体替换替身,而当我们的代码里面也还要就此时因此替身来增援。

看例子:

1
#define PI 3.141592654

  

  在以后之代码中您一味可以以PI
来替代3.141592654,而且若太好就是这么做。不然的话,如果我要拿PI
的精度再加强部分,你是否情愿一个一个底夺修改就串数也?你能够保证不透无产生错?而用PI
的语句,我们也惟独待改一坏(这是特别快捷之)。

 

这种状态尚无是太要命的,我们再度看一个例:

1
#define ERROR_POWEROFF  -1

  如果您以代码里不用ERROR_POWEROFF
这个宏而用-1,尤其当函数返回错误代码的时段(往往一个开发一个系统要定义很多错误代码)。肯怕上帝都爱莫能助知道-1
表示的是什么意思吧。这个-1,我们一般叫“魔鬼数”,上帝遇到她呢会见疯狂的。所以,我劝你代码里肯定不要出现“魔鬼数”。(这里是打代码可读性的角度展开考虑!)

  但是我们使用define来定义数值类的数量,一般只是用来定义  常量
,如果 要定义有变量,则可用c语言中const这个根本字。

  我们曾经讨论了const 这个首要字,我们清楚const
修饰的数码是起型的,而define
宏定义之多少尚未路。为了安全,我提议您之后当概念有宏常数的时刻用const代替,编译器会让const
修饰的独自念变量做项目校验,减少不当的或许。

  但必然要是专注const修饰的免是常量而是readonly 的变量,const
修饰的独念变量不可知因此来作为定义数组的维数,也无可知放在case 关键字后。

 

2.施用define来定义 字符串宏常量

 

除开定义宏常数之外,经常还用来定义字符串,尤其是路径

 

1
2
A),#define ENG_PATH_1 E:\English\listen_to_this\listen_to_this_3
B),#define ENG_PATH_2 “E:\English\listen_to_this\listen_to_this_3”

 

啊,到底哪一个不利吧?如果路径太丰富,一行写下去比较别回怎么收拾?用反斜杠接续符
‘\’ 啊:

 

1
C), #define ENG_PATH_3 E:\English\listen_to_this\listen\_to_this_3  

 

还无觉察问题?这里用了4
个反斜杠,到底孰是连续符?回去省接续符反斜杠。

反而斜杠作为后续符时,在同行业其后面不能够还闹其它字符,空格都深。所以,只有最终一个反而斜杠才是接续符。至于A)和B),那如果扣押而怎么用了,既然define
宏只是简短的更迭,那被ENG_PATH_1 加上双引号不纵成了:“ENG_PATH_1”。

可要留意:有的系统里确定路径的设为此双相反斜杠“\\”,比如(这是天经地义的本子):

1
#define ENG_PATH_4 E:\\English\\listen_to_this\\listen_to_this_3

 

3.用define 宏定义 注释符号

方对define 的用都生简单,再看看下面的例证:

1
2
3
4
5
6
#define BSC //
#define BMC /*
#define EMC */
 
D),BSC my single-line comment
E),BMC my multi-line comment EMC

 

  D)和E)都错,为什么吧?因为注释先于预处理指令给拍卖,当就片推行让开展成//…或/*…*/时,注释已处理完毕,此时还出现//…或/*…*/自然错误.(这同修需要对编译预处理有所知,才能够体会。看来我还得重复写一首就面的章。)

  因此,试图用宏开始还是结一截注释是十分的。

 

4.为此define 宏定义表达式

 

这些还吓明,下面来点起“技术含量”的,定义一年有略秒:

1
#define SEC_A_YEAR 60*60*24*365

  

是定义尚无错吧?很遗憾,很有或错了,至少不可靠。你发没发考虑在16
各系统下将如此一个数赋给整型变量的时光恐怕会见产生溢起?一年起略秒为非容许是负数吧。

改一下:

1
#define SEC_A_YEAR (60*60*24*365)UL

与此同时冒出一个题材,这里的括号到底需不需要呢?继续看一个事例,定义一个宏函数,求x
的平方:

1
#define SQR (x) x * x

  

针对怪?试试:假设x 的价也10,SQR (x)被轮换后变为10*10。没有问题。

重复试试:假设x 的价是个表达式10+1,SQR
(x)被轮换后成10+1*10+1。问题来了,这并无是自己怀念如果抱的。怎么处置?括号括起来不就终止了?

1
#define SQR (x) ((x)*(x))

极端外层的括号最好吧变更看了,看例子,求少只数之跟:

1
#define SUM (x) (x)+(x)

  

假若x 的价是独表达式5*3,而代码又写成这样:SUM (x)* SUM
(x)。替换后成:(5*3)+(5*3)*(5*3)+(5*3)。又错了!所以最外层的括号最好呢变化看了。我说过define
是只演技高超的替身演员,但为时常打闹大牌。要搞定她事实上挺简单,别吝啬括号就推行了。

专注就一点:宏函数给调用时是为可靠参代换形参。而无是“值传送”。

 

5.宏定义着之空格

 

此外还有一个题目需引起注意,看下面例子:

1
#define SUM (x) (x)+(x)

及时要么定义之宏函数SUM(x)吗?显然不是。编译器认为当下是概念了一个硕大:SUM,其象征的凡(x)
(x)+(x)。

干什么会这样啊?其关键问题还是在于SUM
后面的是空格。所以当定义宏的早晚一定要注意什么时候该用空格,什么时不该用空格。这个空格仅仅在概念的时使得,在运用是宏函数之上,空格会被编译器忽略掉。也就是说,上同样节约定义好之宏函数SUM(x)在运的时候在SUM
和(x)之间留有空格是没有问题的。比如:SUM(3)和SUM (3)的意是同一的。

 

6.#undef

#undef 是为此来撤销宏定义的,用法如下:

1
2
3
4
5
6
7
#define PI 3.141592654
 
 
// code
 
#undef PI  

//下面的代码就非克用PI 了,它早已为收回了宏定义。

 

写好C语言,漂亮的宏定义很要紧,使用宏定义可以预防串,提高可移植性,可读性,方便性
等等。下面罗列部分熟软件受到经常因此得宏定义:

1,防止一个头文件为再度包含

1
2
3
4
5
6
7
#ifndef COMDEF_H
 
#define COMDEF_H
 
//头文件内容
 
#endif

  

2,重新定义有类型,防止由于各种平台以及编译器的差,而出的品种字节数差异,方便移植。这里已经休是#define的范围了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
typedef unsigned char boolean/* Boolean value type. */
typedef unsigned long int uint32; /* Unsigned 32 bit value */
typedef unsigned short uint16; /* Unsigned 16 bit value */
typedef unsigned char uint8; /* Unsigned 8 bit value */
typedef signed long int int32; /* Signed 32 bit value */
typedef signed short int16; /* Signed 16 bit value */
typedef signed char int8; /* Signed 8 bit value */
//下面的不建议使用
typedef unsigned char byte/* Unsigned 8 bit value type. */
typedef unsigned short word; /* Unsinged 16 bit value type. */
typedef unsigned long dword; /* Unsigned 32 bit value type. */
typedef unsigned char uint1; /* Unsigned 8 bit value type. */
typedef unsigned short uint2; /* Unsigned 16 bit value type. */
typedef unsigned long uint4; /* Unsigned 32 bit value type. */
typedef signed char int1; /* Signed 8 bit value type. */
typedef signed short int2; /* Signed 16 bit value type. */
typedef long int int4; /* Signed 32 bit value type. */
typedef signed long sint31; /* Signed 32 bit value */
typedef signed short sint15; /* Signed 16 bit value */
typedef signed char sint7; /* Signed 8 bit value */  

3,得到指定地方及之一个字节或字

1
2
#define MEM_B( x ) ( *( (byte *) (x) ) )
#define MEM_W( x ) ( *( (word *) (x) ) )  

 

 

4,求最好老价值和极端小值

1
2
#define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )
#define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )

  

5,得到一个field在结构体(struct)中的偏移量

1
2
#define FPOS( type, field ) \
/*lint -e545 */ ( (dword) &(( type *) 0)-> field ) /*lint +e545 */

  

6,得到一个结构体中field所占有的字节数

1
#define FSIZ( type, field ) sizeof( ((type *) 0)->field )

  

7,按照LSB格式把个别只字节转化为一个Word

1
#define FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] )

  

8,按照LSB格式把一个Word转化为有限单字节

1
2
3
4
5
#define FLOPW( ray, val ) \
 
(ray)[0] = ((val) / 256); \
 
(ray)[1] = ((val) & 0xFF)

  

9,得到一个变量的地方(word宽度)

1
2
3
#define B_PTR( var ) ( (byte *) (void *) &(var) )
 
#define W_PTR( var ) ( (word *) (void *) &(var) )

  

10,得到一个许之上位和小字节

1
2
3
#define WORD_LO(xxx) ((byte) ((word)(xxx) & 255))
 
#define WORD_HI(xxx) ((byte) ((word)(xxx) >> 8))

  

11,返回一个比X大的卓绝相近的8的翻番

1
#define RND8( x ) ((((x) + 7) / 8 ) * 8 )

  

12,将一个字母转换为题写

1
#define UPCASE( c ) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )

  

13,判断字符是不是10前进值的数字

1
#define DECCHK( c ) ((c) >= '0' && (c) <= '9')

  

14,判断字符是无是16上值的数字

1
2
3
4
5
#define HEXCHK( c ) ( ((c) >= '0' && (c) <= '9') ||\
 
((c) >= 'A' && (c) <= 'F') ||\
 
((c) >= 'a' && (c) <= 'f') )

  

15,防止溢起之一个法

1
#define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))

  

16,返回数组元素的个数

1
#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )

  

17,返回一个无符号数n尾的价MOD_BY_POWER_OF_TWO(X,n)=X%(2^n)

1
2
#define MOD_BY_POWER_OF_TWO( val, mod_by ) \
( (dword)(val) & (dword)((mod_by)-1) )

  

18,对于IO空间映射在储存空间的构造,输入输出处理

1
2
3
4
5
6
7
8
9
10
11
#define inp(port) (*((volatile byte *) (port)))
 
#define inpw(port) (*((volatile word *) (port)))
 
#define inpdw(port) (*((volatile dword *)(port)))
 
#define outp(port, val) (*((volatile byte *) (port)) = ((byte) (val)))
 
#define outpw(port, val) (*((volatile word *) (port)) = ((word) (val)))
 
#define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))

  

19,使用有宏跟踪调试 
A N S I标准认证了五个预定义的宏名。它们是:

1
2
3
4
5
_ LINE _
_ FILE _
_ DATE _
_ TIME _
_ STDC _

 

可以定义宏,例如:

当定义了_DEBUG,输出数据信息以及所在文件所在行

1
2
3
4
5
6
7
8
9
#ifdef _DEBUG
 
#define DEBUGMSG(msg,date) printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_)
 
#else
 
#define DEBUGMSG(msg,date)
 
#endif

  

20,宏定义防止使用是错误

因而小括号包含。

例如:

1
#define ADD(a,b) (a+b)

 

do{}while(0)喻词包含多告诉词防止误

例如:

1
2
3
#define DO(a,b) a+b;\
 
a++;

应用时:

1
2
3
4
5
if(….)
 
DO(a,b); //产生错误
 
else

 

解决措施:
代码就偏偏会实施同一破。和一直加花括号来啊界别吗。哦对,不可知不管在程序中,任意加{},组成代码块的。

1
2
3
#define DO(a,b) do{a+b;\
 
a++;}while(0)