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的定义中有两个常见的错误:

  1. 不要将macros的参数括在macros体中的括号中,所以如果这些参数是expression式,在这些expression式中具有不同优先级的运算符可能会引起问题。 这是解决这个问题的一个版本

     #define SQR(x) ((x)*(x)) 
  2. 不止一次地评价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))

这将适用于你传递的任何论点或价值。