C中的macros需要括号
我试图在下面的代码中使用macrosSQR
的定义:
#define SQR(x) (x*x) int main() { int a, b=3; a = SQR(b+5); // Ideally should be replaced with (3+5*5+3), though not sure. printf("%d\n",a); return 0; }
它打印23
。 如果我将macros定义更改为SQR(x) ((x)*(x))
那么输出如预期的那样为64
。 我知道C中的一个macros的调用用macros的定义来替代调用,但我仍然不明白,它是如何计算的23
。
预编译器macros在编译代码之前执行文本replace,所以SQR(b+5)
转换为(b + 5 * b + 5)=(6b + 5)= 6 * 3 + 5 = 23
常规函数调用会在将函数传递给函数之前计算参数(b + 3)的值,但由于macros是预编译replace,所以操作的代数次序变得非常重要。
因为(3+5*3+5 == 23)
。
而((3+5)*(3+5)) == 64
。
最好的办法是不要使用macros :
inline int SQR(int x) { return x*x; }
或者简单地写x*x
。
macros扩大到
a = b+5*b+5;
即
a = b + (5*b) + 5;
那么23。
考虑使用这个macros的macrosreplace:
#define SQR(x) (x*x)
使用b+5
作为参数。 自己做replace。 在您的代码中, SQR(b+5)
将变为: (b+5*b+5)
或(3+5*3+5)
。 现在请记住您的运算符优先级规则: *
before +
。 所以这被评估为: (3+15+5)
或23
。
macros的第二个版本:
#define SQR(x) ((x) * (x))
是正确的,因为你正在使用parens从运算符优先级的效果中修剪macros观参数。
这是一个很好的运算符优先级图表 。
这里要记住的是,你应该习惯于使用parens来屏蔽macros中的任何参数。
macros只是一个直接的文本replace。 预处理之后,您的代码如下所示:
int main() { int a, b=3; a = b+5*b+5; printf("%d\n",a); return 0; }
乘法的运算符优先级高于加法运算符的优先级,因此在计算a的值时,会在两次加法之前完成。 将括号添加到您的macros定义通过以下方法来解决问题:
int main() { int a, b=3; a = (b+5)*(b+5); printf("%d\n",a); return 0; }
加法运算在乘法运算之前进行评估,所以现在先添加,并得到你期望的a = 64
结果。
经过预处理, SQR(b+5)
将被扩展到(b+5*b+5)
。 这显然是不正确的。
在SQR
的定义中有两个常见的错误:
-
不要将macros的参数括在macros体中的括号中,所以如果这些参数是expression式,在这些expression式中具有不同优先级的运算符可能会引起问题。 这是解决这个问题的一个版本
#define SQR(x) ((x)*(x))
-
不止一次地评价macros的论据,所以如果这些论证是有副作用的expression式的话,那么这些副作用就可以被重复使用一次以上。 例如,考虑
SQR(++x)
的结果。通过使用GCC typeof扩展,这个问题可以像这样解决
#define SQR(x) ({ typeof (x) _x = (x); _x * _x; })
这两个问题都可以通过用内联函数replace该macros来解决
inline int SQR(x) { return x * x; }
这需要GCC内联扩展或C99,请参阅6.40内联函数与macros一样快 。
由于macros只是stringreplace,并且在完成过程之前发生。 编译器将没有机会看到macrosvariables及其值。 例如:如果一个macros被定义为
#define BAD_SQUARE(x) x * x
像这样打电话
BAD_SQUARE(2+1)
编译器会看到这个
2 + 1 * 2 + 1
这将导致,也许,意想不到的结果
5
要纠正这种行为,您应该总是用括号括住macrosvariables,例如
#define GOOD_SQUARE(x) (x) * (x)
当这个macros被调用,例如,像这样
GOOD_SQUARE(2+1)
编译器会看到这个
(2 + 1) * (2 + 1)
这将导致
9
另外,下面是一个完整的例子来进一步说明这一点
#include <stdio.h> #define BAD_SQUARE(x) x * x // In macros alsways srround the variables with parenthesis #define GOOD_SQUARE(x) (x) * (x) int main(int argc, char const *argv[]) { printf("BAD_SQUARE(2) = : %d \n", BAD_SQUARE(2) ); printf("GOOD_SQUARE(2) = : %d \n", GOOD_SQUARE(2) ); printf("BAD_SQUARE(2+1) = : %d ; because the macro will be \ subsituted as 2 + 1 * 2 + 1 \n", BAD_SQUARE(2+1) ); printf("GOOD_SQUARE(2+1) = : %d ; because the macro will be \ subsituted as (2 + 1) * (2 + 1) \n", GOOD_SQUARE(2+1) ); return 0; }
把macros观扩张中的每个论点都括在括号里。
定义SQR(x)((x)*(x))
这将适用于你传递的任何论点或价值。