11 | 预处理命令(下):必须掌握的“黑魔法”,让编译器帮你写代码
本次任务
必知必会,查缺补漏
- 深入了解
- 翻译
- 解释
- 总结
本文介绍了预处理命令中的宏定义和条件编译两种重要概念。宏定义通过简单替换实现代码优化,但在复杂替换内容时可读性较差,文章介绍了在行尾加反斜杠的语法以提高可读性。同时,还提到了`__typeof`方法的作用。另外,文章详细介绍了条件编译的语法格式和指令,以及如何定义支持可变参数的log宏。最后,总结了宏定义的基本用法和条件编译的作用,强调了编译器预设的宏对代码可移植性的影响。整体而言,本文通过实例和图示生动地介绍了预处理命令的基本概念和技术特点,为读者提供了深入理解预处理命令的知识。
《人人都能学会的编程入门课》,新⼈⾸单¥59
全部留言(20)
- 最新
- 精选
- Aureliano最开始用#define MAX(a,b) ((a)>(b)?(a):(b)),到a++的时候就得不到预期答案,因为宏定义只是单纯替换语句,待编译文件中就在比较(a)>(b)时调用了一次a++,后面(a):(b)时也调用了一次,于是想到把表达式的值作为变量存储起来,这样就不存在二次调用了,然而还是出现了一系列错误,最后查资料发现如果定义程序段要返回值的话需要在{}外用()扩起,调试之后输出与预期输出一致 #include<stdio.h> #define P(item) printf("%s = %d\n",#item,item) #define MAX(a,b) ({ \ __typeof(a) _a =a; \ __typeof(b) _b =b; \ _a>_b?_a:_b; \ }) int main(){ int a=6; P(MAX(2,3)); P(5+MAX(2,3)); P(MAX(2,MAX(3,4))); P(MAX(2,3>4?3:4)); P(MAX(a++,5)); P(a); return 0; }
作者回复: d(^_^o)非常棒!
2020-02-276 - Linuxer#define log(frm, args...) { \ // 原来这个地方就缺少了反斜线吧 printf("[%s : %d] ",__func__,__LINE__); \ printf(frm, ##args); \ } "##"的作用是对token进行连接,这里的args就是token,如果token为空,那么不进行连接,所以允许省略可变参数
作者回复: 完美!
2020-03-015 - 吕作晶_typeof()作用:声明和已知类型一样类型的新变量
作者回复: yes!
2020-03-293 - 罗耀龙@坐忘茶艺师学编程 我在这,卡了好久…… 1、没想到括号的作用是这么的大…… /*宏定义之傻瓜表达式 修改版*/ #include <stdio.h> #define mul(a, b) (a)* b int main(){ printf("mul(3 ,5) = %d\n", mul(3, 5)); printf("mul(3 + 4, 5) = %d\n", mul(3 + 4, 5)); return 0; } 2、我补上了“空格” /*课文例子修改bug*/ #include <stdio.h> /*下面的define就是在定义log(强化版printf)*/ #define log(frm, args...){\ printf ("所在位置[%s : %d] ",__func__,__LINE__);\ printf (frm, args);\ } /*定义func函数(其中引用上面的log)*/ void func(char *a){ log("a = %s\n", a); } int main(){ printf("请输入要处理的内容:\n"); char a[200] ; scanf("%[^\n]s", a); //这里的%[^\n]s是关键,不然遇到空格就···· printf("a = %s\n", a); log("a = %s\n", a); func(a); return 0; } 3、一开始,我没有读懂题,就在捣腾printf的宏。 然后知道目标是MAX,也是花了大把的时间。 到最后,成品也有一个是不符合输出要求的…… 我就是想不明白为什么a就是会加两次1得8呢? /*作业半成品*/ #include <stdio.h> #define P(item) printf("%s = %d\n", (#item), (item)) #define MAX(a, b) (a > (b) ? (a - 1) : b ) int main(){ int a = 6; P(MAX(2, 3)); P(5 + MAX(2, 3)); P(MAX(2, MAX(3, 4))); P(MAX(2, 3 > 4 ? 3 : 4)); P(MAX(a++, 5)); P(a); return 0; }
作者回复: 非常棒!!可以加我微信交流:huguang_AOA
2020-06-012 - 1043\ 后面加了空格有办法一眼就看出来吗?换编程终端后面的黑白版颜色能看出来吗?宏所替换的计算功能也是先算乘除法后算加减法有括号先算括号吗?编译器预设的宏有标准和非标准的区别,是宏的状态是标准/非标准化,还是编译器是分标准/非标准化?比如同样用c语言编写,其中一份给Linux的gcc编译就是Linux的程序,用华为的方舟编译器编译完成后就是鸿蒙的程序了吗?
作者回复: 1、基本看不出来,有些文本编辑器会把空格显示成一个灰色的暗点,这样的话,是可以看出来的。 2、宏替换以后的内容,就相当于正常的程序代码,正常的程序代码怎么运行,就怎么运行。 3、宏分成标准和非标准的,所谓标准,就是普通话,而每个编译环境多多少少都有自己的口音。 4、你可以这样理解,不过其中的细节还挺多,其实你也可以用gcc编译windows的exe可执行程序,编译是一整套的流程,某些环节依赖于硬件配置,有些环节依赖于操作系统,还有些环节依赖于系统中的默认库文件。总的来说,不管多复杂,目标只有一个,就是把源文件编译成目标机器可执行的可执行程序。
2020-04-082 - doge老师好,我用#define log(frm, args...) log(frm, args)的方式会报错expected expression before ‘)’ token,但用#define log(frm, ...) log(frm, ##__VA_ARGS__) 就不会有问题,这是为什么?
作者回复: 你得应该是 #define log(frm, ...) printf(frm, ##__VA_ARGS__) 吧? 因为后面一种实现方式,加入了 ## 宏连接符,所以允许变参列表中的内容为空。第一种没有 ## 连接符的,不允许内容为空。
2020-02-161 - 微风漂过#define P(item) printf("%s = %d\n", #item, item); #item前面的#,作用是什么?
作者回复: 是把iterm原本要替换的内容变成对应的字符串。你可以自己写一个小的实验性程序,试一下#的作用。
2020-02-051 - 徐洲更__typeof(a) 用于获取a的变量类型 C语言的变量要定义后才能用, swap宏是一个适用于多种数据结构的宏,因此需要根据具体变量声明具体的变量类型
作者回复: d(^_^o)没问题!
2020-01-301 - 吕作晶因为有++这类运算符,使得宏定义基本上都不得不使用__typeof()~不知道为什么感觉把一个事情反而变得特别的麻烦~始终觉得带__的东西,可读性都很差~
作者回复: :-(没办法,如果是我定的标准,肯定把两个下划线去掉。(*^o^*)
2020-03-29 - 🤪HappyJoo#define MAX(x, y) ({\ int _x = x;\ int _y = y;\ _x>_y ? _x : _y;\ })//(a)>(b)?(a):(b)) 记得前后的字母要一致哦 其实我对这个临时变量还是不太理解哈,希望老师能指教。我的理解是,用了临时变量当做替身,丢进去计算,再把结果直接返回。但是在赋值之前,该做的运算都做了,做好之后才赋值给临时变量的。++是在丢进去之前就计算好了,所以a先变成7,然后赋值给临时变量,再丢进去MAX运算得到结果。不然不知道怎么解释它只加了一次嘿嘿嘿。
作者回复: 不是的,宏做的是简单的代码展开和替换,你把相应调用出的宏展开以后,你会看到 int _x = a++; 对于这段代码来说,a++只执行了一次。注意,宏不是函数,丢给宏的参数,宏也不会进行计算,宏做的就是简单的替换。
2020-02-13