第1章-预处理器阶段
- 1)c代码->预处理器处理->编译->...
- 2)宏只是对程序的“文本”起作用,预处理器阶段对宏进行了展开。
一、不能忽视宏定义中的空格
- 测试目标:
用宏模拟一个函数f(x)=x*2的行为
Tips:“宏”和“函数”是两回事
1)testOne.c
//testOne.c #include<stdio.h> #define f(x) x*2 int main() { int num=f(3); printf("%d\n",num); return 0; } //输出 //6
人工模拟“预处理器”过程
上述test.c经过“预处理器”展开之后的样子如下:
//testOne.c宏展开之后 #include<stdio.h> int main() { //关注点如下,只做文本替换 int num=3*2; printf("%d\n",num); return 0; }
2)testTwo.c
//testTwo.c #include<stdio.h> //注意,f和(x)之间已经有个空格了 #define f (x) x*2 int main() { int num=f(7); printf("%d\n",num); return 0; } //输出 //编译错误
解释:此处,f文本将被替换为(x) x2 *文本**
所以,不能忽视宏定义中的空格
二、宏并不是“函数”
testOne.c中,那种模拟宏的方式其实是不够严谨的
比如,要是喜欢认为这种定义宏就是“函数”的人,可能会认为testThree.c会输出0?
//testThree.c #include<stdio.h> #define f(x) x*2 int main() { int num=f(7-7); printf("%d\n",num); return 0; } //输出 //-7
原因:宏它就是“宏”,不要用其他特性来揣测它
宏的特点就是在“预处理器阶段”进行文本替换
//testThree.c宏展开之后 #include<stdio.h> int main() { int num=7-7*2; printf("%d\n",num); return 0; } //输出 //-7
为了预防这种文本一环,引起的由于“优先级”而导致“事与愿违”的现象
建议:
- 1、在宏定义中把“每个参数”都用括号括起来
- 2、将“整个结果表达式”也都用括号括起来
#define f(x) x*2 修改为下面的样子 #define f(x) ( (x) *2 )
三、宏并不是“语句”
四、宏并不是“类型定义”
//编译条件,DevC++,32bit #include<stdio.h> #define one double * typedef double * two; int main() { one a,b; printf("%d %d\n",sizeof(a),sizeof(b)); two c,d; printf("%d %d\n",sizeof(c),sizeof(d)); return 0; } //输出 //4 8 //4 8
宏展开之后,关键部分
one a,b; //预处理阶段,宏展开为 double * a,b;//a是指针变量,b是普通变量 two c,d; //编译阶段处理后,c和d都是指针变量
附)总结
- 1、宏只是对程序的“文本”起作用,预处理器阶段对宏进行了展开。
- 2、建议
- 在宏定义中把“每个参数”都用括号括起来
- 将“整个结果表达式”也都用括号括起来
- 3、宏和“函数”/“语句”/“类型定义”等的不同,本质在于,宏是文本替换。