C中宏的括号需要

时间:2012-05-30 16:25:27

标签: c macros c-preprocessor parentheses

我尝试在以下代码中使用宏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

8 个答案:

答案 0 :(得分:30)

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

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

答案 1 :(得分:10)

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

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

执行此操作的最佳方法是不使用宏

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

或者只是写x*x

答案 2 :(得分:7)

考虑使用此宏替换宏:

#define SQR(x) (x*x)

使用b+5作为参数。自己做替换。在您的代码中,SQR(b+5)将变为:(b+5*b+5)(3+5*3+5)。现在请记住*之前的运算符优先级规则:+。因此评估为:(3+15+5)23

宏的第二个版本:

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

是正确的,因为你正在使用parens来根据运算符优先级的效果来表示你的宏参数。

This page解释C的操作员偏好有一个很好的图表。 Here's C11参考文件的相关部分。

这里需要记住的是,你应该养成使用parens来屏蔽宏中任何参数的习惯。

答案 3 :(得分:6)

宏扩展为

 a = b+5*b+5;

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

所以23。

答案 4 :(得分: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结果。

答案 5 :(得分:2)

预处理后,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; })
    
  3. 可以通过使用内联函数

    替换该宏来解决这两个问题
       inline int SQR(x) { return x * x; }
    

    这需要GCC内联扩展或C99,请参阅6.40 An Inline Function is As Fast As a Macro

答案 6 :(得分:0)

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

#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;
}

答案 7 :(得分:-2)

将宏扩展中的每个参数都括在括号中。

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

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