【发布时间】:2021-01-20 07:26:13
【问题描述】:
#include <stdio.h>
#define CUBE(x) (x * x * x)
int main() {
printf("%d", CUBE(4+5));
return 0;
}
【问题讨论】:
标签: c c-preprocessor
#include <stdio.h>
#define CUBE(x) (x * x * x)
int main() {
printf("%d", CUBE(4+5));
return 0;
}
【问题讨论】:
标签: c c-preprocessor
这是宏在编译过程中的扩展方式:
printf("%d", (4+5 * 4+5 * 4+5));
因为* 的优先级高于+,所以这个表达式被评估为(4 + (5 * 4) + (5 * 4) + 5),产生49 而不是预期的729。
为避免此类运算符优先级问题,所有宏参数必须在宏定义以及表达式本身中用括号括起来:
#define CUBE(x) ((x) * (x) * (x))
但是请注意,CUBE 的这种扩展会多次计算 x,如果宏参数有副作用,例如 CUBE(i++),这是一个问题。
为避免所有这些问题,请使用函数并让编译器对其进行优化:
int cube(int x) {
return x * x * x;
}
您可以在此函数定义前添加static inline,但现代优化器仍会在没有此的情况下内联该函数。
【讨论】:
宏会将代码转为:
printf("%d", (4+5 * 4+5 * 4+5));
实际上是:
printf("%d", 4 + (5*4) + (5*4) + 5); // 29
如果你想用立方9 得到729,你应该写CUBE((4+5))。
【讨论】:
inline向编译器建议)。
CUBE(x++))的宏魔法数量使类似函数的宏成为一个非常糟糕的主意。最好放弃它们,对简单的定义使用宏,对其他所有内容使用内联建议的函数。
#define CUBE(x) ((x)*(x)*(x))
C 预处理器会将 x 的所有实例替换为 4+5,从而产生以下代码:
i = 4+5*4+5*4+5;
(先乘法,后加法)
【讨论】:
如果要添加数字,则需要输入CUBE((4+5)) 之类的输入,然后发送至CUBE。因为CUBE(4+5) 基本上扩展为4+5*4+5*4+5,因为它将整个4+5 设置为x。所以,4+5*4+5*4+5 = 4+20+20+5 首先是乘法,然后相加得到49。
定义像#define CUBE(x) ((x)*(x)*(x)) 这样的宏,它实际上首先对每个(x) 执行(4+5) 操作,然后执行* 操作。
另一种方法是在调用宏时只使用CUBE((4+5)),它基本上是先将两个数字相加(4+5) = 9,然后再做CUBE(9),例如:
#include<stdio.h>
#define CUBE(x) (x * x * x)
int main( )
{
printf("%d", CUBE((4+5)));
return 0;
}
【讨论】:
阅读Modern C,然后阅读n1570 草案C 标准,以及GCC 和GDB 和CPP 的文档。另请参阅this C reference 网站。
从现有的开源项目中汲取灵感,例如在github,或GNU software。
使用最近的GCC 编译器,invoke it 为gcc -Wall -Wextra -g。也可以使用-C -E 选项来获取预处理的表单。
您也可能对 GCC 的 statement-expr 扩展感兴趣。
您的CUBE(4+5) 被宏扩展为4+5*4+5*4+5,根据C operators 的优先级计算为4+(5*4)+(5*4)+5。
考虑编写一个 static inline 之类的函数
static inline int cube(int x) { return x*x*x; }
或者如果你需要一个宏,至少
#define CUBE(X) ((X)*(X)*(X))
这不适用于 CUBE(i++)(而使用 inline 函数时,cube(i++) 会执行您希望它执行的操作:将 i 递增一次!)。
顺便说一句,您可以使用GPP 或GNU m4(或您自己的生成器,或GNU bison)来生成一些C 代码。根据经验,用ASTs 思考:当你生成 C 代码时,会发出很多无用的括号,例如在Chicken Scheme、SWIG 或CAIA 或我的manydl.c 中
您也可以在代码中使用Clang static analyzer(也可以使用Frama-C)。
【讨论】: