1. 预定义符号
C语⾔设置了⼀些预定义符号,可以直接使⽤,预定义符号也是在预处理期间处理的。
2. #define定义常量
#define name stuff
如果定义的 stuff过⻓,可以分成⼏⾏写,除了最后⼀⾏外,每⾏的后⾯都加⼀个反斜杠(续⾏ 符)。 而且不要;
3. #define定义宏
#define机制包括了⼀个规定,允许把参数替换到⽂本中,这种实现通常称为宏(macro)或定义宏 (definemacro)。
#define name( parament-list ) stuff
其中的 parament-list 是⼀个由逗号隔开的符号表,它们可能出现在stuff中。
举个例子吧
#define SQUARE(x) ((x) * (x)) 这个其实就是求平方,我们在使用的时候要注意这是直接替换的,所有千万不要忘记加括号
4. 带有副作⽤的宏参数
当宏参数在宏的定义中出现超过⼀次的时候,如果参数带有副作⽤,那么你在使⽤这个宏的时候就可 能出现危险,导致不可预测的后果。副作⽤就是表达式求值的时候出现的永久性效果。
举个例子
x+1;//不带副作⽤
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);//输出的结果是什么?
你会惊讶的发现输出的结果竟然不是xy中任意一个数,我们只需要把全部替换就能找到原因了
5. 宏替换的规则
在程序中扩展#define定义符号和宏时,需要涉及⼏个步骤。
1. 在调⽤宏时,⾸先对参数进⾏检查,看看是否包含任何由#define定义的符号。如果是,它们⾸先 被替换。
2. 替换⽂本随后被插⼊到程序中原来⽂本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果⽂件进⾏扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上 述处理过程。
注意:
1. 宏参数和#define定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
6. 宏函数的对⽐
和函数相⽐宏的劣势:
1. 每次使⽤宏的时候,⼀份宏定义的代码将插⼊到程序中。除⾮宏⽐较短,否则可能⼤幅度增加程序 的⻓度。
2. 宏是没法调试的。
3. 宏由于类型⽆关,也就不够严谨。
4. 宏可能会带来运算符优先级的问题,导致程容易出现错。
7. #和##
#运算符将宏的⼀个参数转换为字符串字⾯量。它仅允许出现在带参数的宏的替换列表中。
#运算符所执⾏的操作可以理解为”字符串化“。
#define PRINT(n) printf("the value of "#n " is %d", n);
若a使用进去结果为the value of a is 10
## 可以把位于它两边的符号合成⼀个符号,它允许宏定义从分离的⽂本⽚段创建标识符。 ## 被称 为记号粘合
举个例子
#define GENERIC_MAX(type)
type type##_max(type x, type y)
return (x>y?x:y);
这样就会避免type被认成名字的问题
8. 命名约定
把宏名全部⼤写 函数名不要全部⼤写
9. #undef
这条指令⽤于移除⼀个宏定义。
如果现存的⼀个名字需要被重新定义,那么它的旧名字⾸先要被移除
10. 命令⾏定义
许多C的编译器提供了⼀种能⼒,允许在命令⾏中定义符号。⽤于启动编译过程。 例如:当我们根据同⼀个源⽂件要编译出⼀个程序的不同版本的时候,这个特性有点⽤处。
11. 条件编译
在编译⼀个程序的时候我们如果要将⼀条语句(⼀组语句)编译或者放弃是很⽅便的。因为我们有条 件编译指令。
调试性的代码,删除可惜,保留⼜碍事,所以我们可以选择性的编译。
#ifdef __DEBUG__
printf("%d\n", arr[i]);//为了观察数组是否赋值成功。
#endif __DEBUG__
12. 头⽂件的包含
引号和<>
13. 其他预处理指令
可以自己了解