37

我尝试SQR在以下代码中使用宏的定义:

#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。如果我将宏定义更改为,SQR(x) ((x)*(x))则输出如预期的那样,64. 我知道在 C 中调用宏会用宏的定义替换调用,但我仍然不明白它是如何计算23的。

4

8 回答 8

39

预处理器宏在编译代码之前执行文本替换,因此 SQR(b+5)转换为 (b+5*b+5) = (6b+5) = 6*3+5 = 23

常规函数调用会在将参数 (b+3) 传递给函数之前计算参数的值,但由于宏是预编译替换,因此运算的代数顺序变得非常重要。

于 2012-05-30T16:28:05.930 回答
17

考虑使用此宏进行宏替换:

#define SQR(x) (x*x)

用作论据b+5。自己更换。在您的代码中,SQR(b+5)将变为:(b+5*b+5)(3+5*3+5)。现在记住您的运算符优先规则:*before +。所以这被评估为:(3+15+5)23

宏的第二个版本:

#define SQR(x) ((x) * (x))

是正确的,因为您使用括号来保护宏参数免受运算符优先级的影响。

这个解释操作员对 C 的偏好的页面有一个很好的图表。这是C11 参考文档的相关部分。

这里要记住的是,您应该养成使用括号始终屏蔽宏中的任何参数的习惯。

于 2012-05-30T16:31:01.820 回答
11

因为(3+5*3+5 == 23).

((3+5)*(3+5)) == 64.

最好的方法是不使用宏

inline int SQR(int x) { return x*x; }

或者干脆写x*x

于 2012-05-30T16:28:00.050 回答
8

宏扩展为

 a = b+5*b+5;

IE

 a = b + (5*b) + 5;

所以23。

于 2012-05-30T16:27:30.063 回答
4

预处理后,SQR(b+5)将扩展为(b+5*b+5). 这显然是不正确的。

的定义中有两个常见的错误SQR

  1. 不要将宏的参数括在宏体中的括号中,因此如果这些参数是表达式,则这些表达式中具有不同优先级的运算符可能会导致问题。这是解决此问题的版本

    #define SQR(x) ((x)*(x))
    
  2. 多次评估宏的参数,因此如果这些参数是具有副作用的表达式,则这些副作用可能会被多次采用。例如,考虑 的结果SQR(++x)

    通过使用 GCC typeof扩展,可以像这样解决这个问题

    #define SQR(x) ({ typeof (x) _x = (x); _x * _x; })
    

这两个问题都可以通过用内联函数替换该宏来解决

   inline int SQR(x) { return x * x; }

这需要 GCC 内联扩展或 C99,请参阅6.40 内联函数与宏一样快

于 2014-05-27T12:47:16.697 回答
2

宏只是直接的文本替换。预处理后,您的代码如下所示:

int main()
{
    int a, b=3;
    a = b+5*b+5;
    printf("%d\n",a);
    return 0;
}

乘法的运算符优先级高于加法,因此在计算 的值时在两次加法之前完成a。在宏定义中添加括号可以通过以下方式解决问题:

int main()
{
    int a, b=3;
    a = (b+5)*(b+5);
    printf("%d\n",a);
    return 0;
}

带括号的运算在乘法之前进行评估,因此现在首先进行加法,并且您会得到a = 64预期的结果。

于 2012-05-30T16:34:44.703 回答
1

因为宏只是字符串替换,它发生在完成过程之前。编译器将没有机会看到宏变量及其值。例如:如果一个宏被定义为

#define BAD_SQUARE(x)  x * x 

并像这样称呼

BAD_SQUARE(2+1) 

编译器会看到这个

2 + 1 * 2 + 1

这可能会导致意想不到的结果

5

要纠正这种行为,您应该始终用括号括住宏变量,例如

#define GOOD_SQUARE(x)  (x) * (x) 

例如,当调用此宏时,像这样

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;
}
于 2017-01-09T20:35:36.297 回答
-3

只需将宏扩展中的每个参数括在括号中即可。

#define SQR(x) ((x)*(x))

这适用于您传递的任何参数或值。

于 2016-03-13T11:13:14.377 回答