预处理阶段,要做的一件事就是对#define的处理
- 宏定义
宏定义分两种,变量式宏定义和函数式宏定义,具体怎么使用我不想讲,主要讲一些注意点吧。
1)变量型宏定义其实是没有类型的,它只是一个符号,在预处理阶段将符号替换;
2)由于它不属于任何数据类型,所以不会被分配内存;
3)进一步,在函数调用中,它不能作为参数传递,因为无论是传值还是传引用,参数都是有类型的,都占用内存。
4)重复定义宏的时候,定义内容必须一模一样,如果想要重新定义,需要借助#undef,#undef的多次使用并不会报错。
5)宏定义的实现并不是只有#define PI 3.14这一种方式实现,可以通过gcc -D选项定义一个宏,gcc -c -DPI=3.14 main.c;gcc -c -DMACHINE=68000 main.c;这种办法需要在MAKEFILE中配置。 - 条件预处理指令
在源代码的配置管理当中通常有很多类似如下的几行代码:#if MACHINE == 68000 int x; #elif MACHINE == 8086 long x; #else /* all others */ #error UNKNOWN TARGET MACHINE #endif
只是看代码不难知道什么意思,但应该尝试与实际场景联系起来。现在有两个平台,平台1要求MACHINE=68000时,全局变量x为整型,平台1要求MACHINE=8086时,全局变量x为长整型。
更近一步地,我们可以更复杂
#if MACHINE == 68000 代码1 #elif MACHINE == 8086 代码2 #else /* all others */ #error UNKNOWN TARGET MACHINE #endif
这样平台1在MACHINE=68000时可以执行一串代码,平台2同理。
- 编译器还有自己定义的预处理指令,
例如__FILE__的展开是当前源文件的绝对路径,是一个字符串。#include <stdio.h> using namespace std; int main(){ printf("The file is:%s",__FILE__); }
输出结果是:
The file is:/Users/liujinyang/CLionProjects/leetcode/consumer_producer/main.cpp
还有__LINE__的展开是当前代码所在行号,是一个整数。
#include <stdio.h> using namespace std; int main(){ printf("The file is:%s\n",__FILE__); printf("The line is:%d",__LINE__); }
输出结果是:
The file is:/Users/liujinyang/CLionProjects/leetcode/consumer_producer/main.cpp
The line is:120
这些都不是通过#define实现的,因为展开结果随着位置变化而变化,他们是编译器内建的特殊宏实现的。
此外,C99还引入了一个特殊的标志符__func__,它是一个变量名,而不是宏定义,作用跟以上两个宏定义类似,用来显示所处函数的函数名。
#include <stdio.h> using namespace std; void fuc1(){ printf("%s\n",__func__); } void fuc2(){ printf("%s\n",__func__); } int main(){ printf("%s\n",__func__); fuc1(); fuc2(); return 0; }
输出结果是:
main
fuc1
fuc2