何时可以省略宏中参数的括号?

通常我常常觉得围绕宏定义中的参数的一些括号是多余的。 把一切都括起来太不方便了。 如果我可以保证参数不需要括号,我可以省略括号吗? 或者强烈建议将它们括起来?

我写的时候想出了这个问题:

#define SWAP_REAL(a, b, temp) do{double temp = a; a = b; b= temp;}while(0) 

我认为如果参数在宏中显示为l值,则可以省略括号,因为这意味着参数出现时没有其他操作。

我的理由是:

  1. 赋值符号的关联优先级仅高于逗号。
  2. 您不能将编译器混淆为认为您的参数是带有逗号的表达式。 例如, SWAP(a, b, b)将不会被成功解释为

     do{double temp = a, b; a, b = b; b= temp;}while(0) 

    哪个可以通过编译。

我对吗? 任何人都可以给我一个反例吗?

在以下示例中,

 #define ADD(a, b) (a += (b)) 

我认为这个论点不需要用括号括起来。 在这种特殊情况下,既不需要参数b ,对吗?

@JaredPar:

  #include  #define ADD(a, b) (a += (b)) int main(){ int a = 0, b = 1; ADD(a; b, 2); return 0; } 

这在我的VS2010上无法成功编译。 Error C2143: syntax error : missing ')' before ';'


简而言之,您不需要将在宏中显示为l值的参数括起来,但强烈建议您将它们全部括起来。

宏规则:

  1. 不要制作带副作用的宏!
  2. 对于没有副作用的宏,只需将所有参数括号括起来,不要再想到了!
  3. 至于有副作用的宏,停止迷恋! 将它们全部括起来! 肌钙蛋白

如果在表达式中使用任何不是最低优先级的运算符,则省略它是不安全的。 我相信那会是逗号。

如果a包含一个低优先级的表达式,如1 || 2 ,那么op是一些运算符,如+*等,总是会绑定错误 1 || 2

注意我并没有声称在这些情况下它是安全的。 有更多创造性的方法来打破宏。 顺便说一句,首先不要使用带副作用的宏。 更一般地,不要将宏用作函数。 (参见,例如,Effective C ++)。

这是一个显示出明显差异的案例

 ADD(x;y, 42) 

使用parens会导致编译错误,但如果没有它会导致编译代码。

 (x;y) += 42; // With parens errors x;y += 42; // Without parens compiles 

这可能看起来像一个愚蠢的例子,但可能将宏组合在一起很容易导致奇怪的代码表达式,如上所述。

为什么要冒这个机会? 它只有2个字符

有些宏用于连接元素以生成字符串(可能使用#运算符),或使用##运算符从宏参数构建标识符。 在这种情况下,您不会将参数括起来。

另外,我认为当宏参数本身作为函数参数传递时,你并不一定要将它们括起来:

 #define CALLOC(s, n) calloc(s, n) 

你可以玩恶魔游戏调用这样一个宏( CALLOC({3, 4}) ),但你得到你应得的(编译错误) – 我不知道一种方法来调用那个宏,如果不是您编写与calloc()直接调用相同的参数的宏。

但是,如果您在大多数算术表达式中使用参数,那么您需要将它们包装在括号中:

 #define MIN(x, y) (((x) < (y)) ? (x) : (y)) 

显然,如果你用带副作用的参数调用它,那么你得到的就是你得到的。 但这些论点不会被误解,因为如果你写的话:

 #define MIN(x, y) x < y ? x : y 

然后将其调用为:

 MIN(x = 3 * y + 1, y = 2 * x - 2); 

Moon的评论建议使用SWAP_INT宏。

当使用默认选项编译时,使用该宏的以下代码干净地编译,但无法使用-DWITH_PARENTHESES设置进行编译。

 #include  #ifdef WITH_PARENTHESES #define SWAP_INT(a, b) do { int temp = (a); (a) = (b); (b) = temp; } while (0) #else #define SWAP_INT(a, b) do { int temp = a; a = b; b = temp; } while (0) #endif int main(void) { int p = 319; int q = 9923; int x = 23; int y = 300; printf("p = %8d, q = %8d, x = %8d, y = %8d\n", p, q, x, y); SWAP_INT(p, q); // OK both ways SWAP_INT(x, y); // OK both ways printf("p = %8d, q = %8d, x = %8d, y = %8d\n", p, q, x, y); SWAP_INT(x /= y, p *= q); // Compiles without parentheses; fails with them printf("p = %8d, q = %8d, x = %8d, y = %8d\n", p, q, x, y); return 0; } 

输出:

 p = 319, q = 9923, x = 23, y = 300 p = 9923, q = 319, x = 300, y = 23 p = 41150681, q = 13, x = 0, y = 3165437 

这不是交换整数的安全或有效方式 - 没有括号的宏不是一个好主意。