一:预定义符号
1.__FILE__ 进⾏编译的源⽂件 打印的是地址
2.__LINE__ ⽂件当前的⾏号
3:__DATE__⽂件被编译的⽇期
4:__TIME__ ⽂件被编译的时间
二: #define 定义常量
#define MAX 1000
三:#define定义宏
#define SQUARE( x ) x * x
对数值表达式进⾏求值的宏定义都应该⽤这种⽅式加上括号,避免在使⽤宏时由于参数中的
操作符或邻近操作符之间不可预料的相互作⽤。
四. 带有副作⽤的宏参数
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
...
x = 5;
y = 8;
z = MAX(x++, y++);
printf("x=%d y=%d z=%d\n", x, y, z);/
结果为x=6 y=10 z=9
五:宏替换的规则
1. 在调⽤宏时,⾸先对参数进⾏检查,看看是否包含任何由#define定义的符号。如果是,它们⾸先
被替换。
2. 替换⽂本随后被插⼊到程序中原来⽂本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果⽂件进⾏扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上
述处理过程
注意:
1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
六:宏函数的对⽐
⽤于调⽤函数和从函数返回的代码可能⽐实际执⾏这个⼩型计算⼯作所需要的时间更多。所以宏⽐
函数在程序的规模和速度⽅⾯更胜⼀筹。
2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使⽤。反之
这个宏怎可以适⽤于整形、⻓整型、浮点型等可以⽤于 > 来⽐较的类型。宏的参数是类型⽆关
的。
和函数相⽐宏的劣势:
1. 每次使⽤宏的时候,⼀份宏定义的代码将插⼊到程序中。除⾮宏⽐较短,否则可能⼤幅度增加程序
的⻓度。
2. 宏是没法调试的。
3. 宏由于类型⽆关,也就不够严谨。
4. 宏可能会带来运算符优先级的问题,导致程容易出现错。
七:
1 #运算符
我们有⼀个变量 int a = 10; 的时候,我们想打印出: the value of a is 10 .
就可以写:
#define PRINT(n) printf("the value of "#n " is %d", n);
2 ## 运算符
## 可以把位于它两边的符号合成⼀个符号,它允许宏定义从分离的⽂本⽚段创建标识符。 ## 被称
为记号粘合
八:命名约定
1:把宏名全部⼤写
2:函数名不要全部⼤写
九:#undef
这条指令⽤于移除⼀个宏定义。
十:命令⾏定义
当我们根据同⼀个源⽂件要编译出⼀个程序的不同版本的时候,这个特性有点⽤处。(假定某
个程序中声明了⼀个某个⻓度的数组,如果机器内存有限,我们需要⼀个很⼩的数组,但是另外⼀个机器内存⼤些,我们需要⼀个数组能够⼤些。
linux 环境演⽰ gcc -D ARRAY_SIZE=10 programe.c
十一:
条件编译
#if 常量表达式
#endif
//常量表达式由预处理器求值。
如:
#define __DEBUG__ 1
#if __DEBUG__
#endif
2.多个分⽀的条件编译
#if 常量表达式
#elif 常量表达式
#else
#endif
3.判断是否被定义
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol
.嵌套指令
#if defined(OS_UNIX)
#ifdef OPTION1
unix_version_option1();
#endif
#ifdef OPTION2
unix_version_option2();
#endif
#elif defined(OS_MSDOS)
#ifdef OPTION2
msdos_version_option2();
#endif
#endif