ToB企服应用市场:ToB评测及商务社交产业平台

标题: 条件编辑及宏定义学习小结 [打印本页]

作者: 自由的羽毛    时间: 2024-5-21 22:42
标题: 条件编辑及宏定义学习小结
​        条件编译(也称为预处置惩罚)是一种在编译阶段控制代码是否包罗进最终编译单位的技术。这通常通过使用预处置惩罚器指令(如#if, #ifdef, #ifndef, #else, #elif, 和 #endif)来完成。而条件编译通常是和宏联系在一起,因此说宏带有不消来回切换,宏替换发生在编译的预处置惩罚阶段,省区函数切换的时间花销,没有实参形参盘算等优点。
​                        因此本次主要记载条件编译,并同时记载宏定义所必要注意的部门细节。
第一种情势
  1. #ifdef MACRO
  2.         some statements
  3. #endif
复制代码
如果定义了宏 MACRO,则编译some statements,否则不编译。


例如下面这个简单函数:
  1. #include <stdio.h>
  2. int main(int argc, char **argv)
  3. {
  4.     printf("条件编译的用法演示\n");
  5. #ifdef HEL
  6.     printf("Hello world\n");
  7. #endif
  8.     return 0;
  9. }
复制代码
当正常编译时,没有执行宏定义的选项,会出现下面的情况:
  1. rice@rice:/mnt/f/$ gcc open.c -o open
  2. rice@rice:/mnt/f/$ ./open
  3. 条件编译的用法演示
复制代码
当编译时添加-HEL选项,提前增加DEL的宏定义,满足#ifdef的条件,结果如下:
  1. rice@rice:/mnt/f/$ gcc open.c -DHEL -o open
  2. rice@rice:/mnt/f/$ ./open
  3. 条件编译的用法演示
  4. Hello world
复制代码
第二种情势
  1. #ifnodef MACRO
  2.         some statements
  3. #endif
复制代码
​         如果没定义宏 MACRO,则编译some statements,否则不编译。与第一种情势正好相反,最常用于头文件中,使得头文件的内容不会被重复包罗。

  1. #ifndef GET_TIME_H
  2. #define GET_TIME_H
  3. #include <time.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include "font.h" //字体函数
  8. void get_Time(int *lcd_mp);
  9. #endif
复制代码
​        在我的get_Time.h头文件中,使用了#ifndef, #define, 和 #endif这三个预处置惩罚器指令来确保头文件的内容只被包罗一次,纵然在多个源文件中多次包罗了此头文件解释如下:
第三种情势
  1. #if expression
  2.         some statements
  3. #endif
复制代码
​        如果expression为真(非零),则编译some statements,否则不编译。如果expression是一个宏,则必须是一个整数或一个整形表达式。


下面是Linux源码部门内容
  1. # if defined __USE_MISC || defined __USE_XOPEN
  2. #  define S_ISVTX        __S_ISVTX
  3. # endif
复制代码
在Linux源码可常常看到条件编译的内容,在之后调试BUG,函数封装的头文件中也会常常用到,必要纯熟掌握。
宏的应用

​     宏分为带参数和不带参数的宏。不带参数的宏非常简单,是在使用的时间举行简单的文本替换,不再赘述。必要特别掌握的是带参数的宏。以下使用一个例子,来总结带参数宏使用的几个要点:
  1. #define MUL1(a, b) a *b + a *b           
  2. #define MUL2(a, b) (a) * (b) + (a) * (b) // 每个参数增加括号
  3. #define MUL3(a, b)                   \
  4.     ({                               \
  5.         int aa = a;                  \
  6.         int bb = b;                  \
  7.         ((aa) * (bb) + (aa) * (bb)); \
  8.     })
复制代码
使用时同样是文本替换,却能实现不一样的结果,例如上述宏定义,引用时,代码及得到的结果如下:
  1. int main(int argc, char **argv)
  2. {
  3.     int a=1;
  4.     int b=2;
  5.     int c1 = 0, c2 = 0, c3 = 0;
  6.     c1 = MUL1(a+a, b+b);
  7.     c2 = MUL2(a+a, b+b);
  8.     c3 = MUL3(a+a, b+b);
  9.     printf("c1=%d c2=%d c3=%d", c1, c2, c3);
  10.     return 0;
  11. }
  12. 得到的结果:c1=10 c2=16 c3=16
复制代码
由于宏定义只举行文本替换,很容易看出三者的区别,预处置惩罚后,文本替换如下:
  1.     c1 = MUL1(a, b)=1+1*2+2+1+1*2+2;
  2.     c2 = MUL2(a, b)=(1+1)*(2+2)+(1+1)*(2+2);
  3.     c3 = MUL3(a, b)=(1+1)*(2+2)+(1+1)*(2+2);
复制代码
再举个例子,代码及得到的结果如下:
  1. int main(int argc, char **argv)
  2. {
  3.     int a = 1;
  4.     int b = 2;
  5.     int a1 = 1;
  6.     int b1 = 2;
  7.     int a2 = 1;
  8.     int b2 = 2;
  9.     int c1 = 0, c2 = 0, c3 = 0;
  10.     c1 = MUL1(a, b++);
  11.     c2 = MUL2(a1, b1++);
  12.     c3 = MUL3(a2, b2++);
  13.     printf("c1=%d c2=%d c3=%d", c1, c2, c3);
  14.     return 0;
  15. }
  16. 得到的结果:c1=5 c2=5 c3=4
复制代码
由于宏定义只举行文本替换,预处置惩罚后,文本替换如下:
  1.     c1 = MUL1(a, b)=a*b++ +a*b++=1*2+1*3=5
  2.     c2 = MUL2(a1, b1)=(a1)*(b1++)+(a1)*(b1++)=1*2+1*3=5
  3.     c3 = MUL3(a2, b2)=   
  4.         ({                               \
  5.         int aa = a2;                  \
  6.         int ba = b2++;                  \
  7.         ((a1) * (b1) + (a1) * (b1)); \
  8.     })                                =1*2+1*2=4       
复制代码
因此,对于宏定义可得到如下小结
1.对于带参数的宏定义,牢记要对于每个元素增加括号,以免运算优先级影响结果。
2.对于在宏定义中会多次出现的参数,应避免。若实在避免不了,可别的定义{(...)}复合语句,使用其他参数取代,且避免使用前缀或后缀运算符(例如“++”,“--”)等。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4