条件编译(也称为预处置惩罚)是一种在编译阶段控制代码是否包罗进最终编译单位的技术。这通常通过使用预处置惩罚器指令(如#if, #ifdef, #ifndef, #else, #elif, 和 #endif)来完成。而条件编译通常是和宏联系在一起,因此说宏带有不消来回切换,宏替换发生在编译的预处置惩罚阶段,省区函数切换的时间花销,没有实参形参盘算等优点。
因此本次主要记载条件编译,并同时记载宏定义所必要注意的部门细节。
第一种情势
- #ifdef MACRO
- some statements
- #endif
复制代码 如果定义了宏 MACRO,则编译some statements,否则不编译。
例
例如下面这个简单函数:- #include <stdio.h>
- int main(int argc, char **argv)
- {
- printf("条件编译的用法演示\n");
- #ifdef HEL
- printf("Hello world\n");
- #endif
- return 0;
- }
复制代码 当正常编译时,没有执行宏定义的选项,会出现下面的情况:- rice@rice:/mnt/f/$ gcc open.c -o open
- rice@rice:/mnt/f/$ ./open
- 条件编译的用法演示
复制代码 当编译时添加-HEL选项,提前增加DEL的宏定义,满足#ifdef的条件,结果如下:- rice@rice:/mnt/f/$ gcc open.c -DHEL -o open
- rice@rice:/mnt/f/$ ./open
- 条件编译的用法演示
- Hello world
复制代码 第二种情势
- #ifnodef MACRO
- some statements
- #endif
复制代码 如果没定义宏 MACRO,则编译some statements,否则不编译。与第一种情势正好相反,最常用于头文件中,使得头文件的内容不会被重复包罗。
例
- #ifndef GET_TIME_H
- #define GET_TIME_H
- #include <time.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include "font.h" //字体函数
- void get_Time(int *lcd_mp);
- #endif
复制代码 在我的get_Time.h头文件中,使用了#ifndef, #define, 和 #endif这三个预处置惩罚器指令来确保头文件的内容只被包罗一次,纵然在多个源文件中多次包罗了此头文件解释如下:
- #ifndef GET_TIME_H:查抄GET_TIME_H这个宏是否已经被定义。如果GET_TIME_H没有被定义,那么编译器会处置惩罚它和与之对应的#endif之间的代码,即引用了包罗的头文件。
- #define GET_TIME_H:这是一个宏定义指令,它定义了一个名为GET_TIME_H的宏,但不为其分配任何值(这样的宏通常被称为“标志”或“标志宏”)。GET_TIME_H被定义成了空的,这个指令的目标是防止在头文件被再次包罗时再次包罗头文件的内容。
- #endif:与#ifndef对应关系,标志着#ifndef条件编译块的结束。
别的,作为一个宏,目前接触到了几种常见写法,不外乎几个小细节:字母全部大写,符号改成"_",且首尾增加 "_",例如上述头文件条件编译宏还可以写为:_GET_TIME_H_
第三种情势
- #if expression
- some statements
- #endif
复制代码 如果expression为真(非零),则编译some statements,否则不编译。如果expression是一个宏,则必须是一个整数或一个整形表达式。
例
下面是Linux源码部门内容- # if defined __USE_MISC || defined __USE_XOPEN
- # define S_ISVTX __S_ISVTX
- # endif
复制代码 在Linux源码可常常看到条件编译的内容,在之后调试BUG,函数封装的头文件中也会常常用到,必要纯熟掌握。
宏的应用
宏分为带参数和不带参数的宏。不带参数的宏非常简单,是在使用的时间举行简单的文本替换,不再赘述。必要特别掌握的是带参数的宏。以下使用一个例子,来总结带参数宏使用的几个要点:- #define MUL1(a, b) a *b + a *b
- #define MUL2(a, b) (a) * (b) + (a) * (b) // 每个参数增加括号
- #define MUL3(a, b) \
- ({ \
- int aa = a; \
- int bb = b; \
- ((aa) * (bb) + (aa) * (bb)); \
- })
复制代码 使用时同样是文本替换,却能实现不一样的结果,例如上述宏定义,引用时,代码及得到的结果如下:- int main(int argc, char **argv)
- {
- int a=1;
- int b=2;
- int c1 = 0, c2 = 0, c3 = 0;
- c1 = MUL1(a+a, b+b);
- c2 = MUL2(a+a, b+b);
- c3 = MUL3(a+a, b+b);
- printf("c1=%d c2=%d c3=%d", c1, c2, c3);
- return 0;
- }
- 得到的结果:c1=10 c2=16 c3=16
复制代码 由于宏定义只举行文本替换,很容易看出三者的区别,预处置惩罚后,文本替换如下:- c1 = MUL1(a, b)=1+1*2+2+1+1*2+2;
- c2 = MUL2(a, b)=(1+1)*(2+2)+(1+1)*(2+2);
- c3 = MUL3(a, b)=(1+1)*(2+2)+(1+1)*(2+2);
复制代码 再举个例子,代码及得到的结果如下:- int main(int argc, char **argv)
- {
- int a = 1;
- int b = 2;
- int a1 = 1;
- int b1 = 2;
- int a2 = 1;
- int b2 = 2;
- int c1 = 0, c2 = 0, c3 = 0;
- c1 = MUL1(a, b++);
- c2 = MUL2(a1, b1++);
- c3 = MUL3(a2, b2++);
- printf("c1=%d c2=%d c3=%d", c1, c2, c3);
- return 0;
- }
- 得到的结果:c1=5 c2=5 c3=4
复制代码 由于宏定义只举行文本替换,预处置惩罚后,文本替换如下:- c1 = MUL1(a, b)=a*b++ +a*b++=1*2+1*3=5
- c2 = MUL2(a1, b1)=(a1)*(b1++)+(a1)*(b1++)=1*2+1*3=5
- c3 = MUL3(a2, b2)=
- ({ \
- int aa = a2; \
- int ba = b2++; \
- ((a1) * (b1) + (a1) * (b1)); \
- }) =1*2+1*2=4
复制代码 因此,对于宏定义可得到如下小结
1.对于带参数的宏定义,牢记要对于每个元素增加括号,以免运算优先级影响结果。
2.对于在宏定义中会多次出现的参数,应避免。若实在避免不了,可别的定义{(...)}复合语句,使用其他参数取代,且避免使用前缀或后缀运算符(例如“++”,“--”)等。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |