这个无括号的C预处理器定义是否安全?

ano*_*nol 27 c++ c-preprocessor

在我的/usr/include目录中,至少有两种#define NULL 0为C++代码1量身定制的变体:

#define NULL 0    // from rpc/types.h
#define NULL (0)  // from libio.h
Run Code Online (Sandbox Code Playgroud)

我觉得必须有一个反例,第一个不安全,但我无法生产它.

否则,是否有一些令人信服的论点,说明为什么在这种情况下不包括括号是安全的(例如,非正式的"正确性证明")?


1即,不包括变量#define NULL ((void*)0),它对C有用但在C++中无效.

unw*_*ind 23

我相信后者可能由于货物结果而出现,即规则/反射总是将预处理器定义放在括号中以获得良好的衡量标准.

  • 他们*可以*有不同的解释.可以使用`if NULL`而另一个不能=) (8认同)
  • @ Mints97真..这不是"看起来"像有效代码,但由于宏中的括号而变得如此,这当然是可怕的但仍然是实际的差异.回答编辑. (5认同)
  • @supercat - `(((a*b)+(c*d)) - (e*f))`强迫我弄清楚那些糟糕的地狱般的愚蠢括号的含义.如果我想这样做,我会在LISP中编程.虽然多余的括号偶尔会有所帮助,但在我看到的堆栈溢出的许多代码示例中,它们只是杂乱无章. (2认同)
  • @PeteBecker:在那个特定的例子中,我通常会同意你的观点,除非目的是特别描述一个操作顺序.然而,围绕宏和他们的论点,我认为冗余往往是一件好事; 虽然将宏扩展到文字可能会有点远,但是在宏具有正负常量混合的情况下,特别是如果某些正值可能需要更改为负值,即使是正文字的额外括号也可能导致更均匀的外观,并确保负三被写为"( - 3)"而不是"-3". (2认同)

Cad*_*hon 23

没有区别.具有较高优先级的唯一运营商::,++--他们是不适用的0,也没有(0).

我看到的唯一有趣的区别是混淆:

#define NULL (0)

void f(int x)
{
  // Do something with x
}

int main()
{
  f NULL; // This code compiles
  return 0;
}
Run Code Online (Sandbox Code Playgroud)


Min*_*s97 8

如果我们谈论安全问题,可以说这#define NULL 0实际上比安全更安全#define NULL (0).

你知道,后者使你能够做到这样的事情:a = func NULL;而不是那样a = func(0);可以在生产C代码中看到它的人的大脑中产生不受控制的核反应.这是非常不安全的,你知道=)


Leu*_*nko 6

既然没有人明确说出来......

是否有一些令人信服的论据,说明为什么在这种情况下不包括括号是安全的(例如,非正式的"正确性证明")?

括号是分组构造.他们采用表达式并将其转换为主表达式(使用标准语法中的名称).无论运算符的优先级如何,完整的主表达式都不能"进入"并由应用于它的运算符拆分.除了函数调用的注释中提到的问题之外if,这就是他们所做的一切; 它们在宏中用于确保扩展结果具有与源中看起来相同的优先级(常量看起来像原子; primary表达式的处理方式与表达式结构中的处理方式相同).

数字0是一个句法原子.它已经被定义为主表达式,因为它是一个文字常量.表达式没有内部结构供操作员拆分,优先级问题甚至不适用.由于括号没有优先级更改,因此将它包装在其中会将primary-expression转换为另一个primary-expression,即它几乎没有任何内容.

参考:C11 6.5.1"主要表达式",C++ 11 5.1.1"主要表达式".