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

Is this parenthesis-free C preprocessor definition safe?

本文关键字:处理器 预处理 定义 是否 安全      更新时间:2023-10-16

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

#define NULL 0    // from rpc/types.h
#define NULL (0)  // from libio.h

我觉得必须有一个反示例,其中第一个是不安全的,但我无法生产。

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


1 也就是说,不包括变体#define NULL ((void*)0),这对于 c 很有用,但在C 中无效。

没有区别。唯一优先级的运营商是::++--,它们不适用于0也不适用于(0)

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

#define NULL (0)
void f(int x)
{
  // Do something with x
}
int main()
{
  f NULL; // This code compiles
  return 0;
}

我相信后者可以由于货物培养而出现,即,规则/反射始终将预处理器定义放在括号中,以备不错。

如果我们谈论的是安全,可以说#define NULL 0实际上比#define NULL (0)更安全。

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

,因为没有人明确将其拼写出来...

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

括号是一个分组结构。他们采用表达式,然后将其转换为A 主表达(使用标准语法中的名称)。无论操作员的优点如何除了在函数呼叫和if的评论中提到的问题外,这就是他们所做的;它们在宏中使用以确保扩展的结果具有与源中看起来相同的优先级(常数看起来像一个原子; a primary-embression 的处理方式与在表达结构)。

数字0是句法原子。由于是一个字面的常数,它已经被定义为A 主要表达。表达式没有内部结构可以使操作员分开,而且优先问题甚至不适用于。由于括号没有更改的优先级,因此将其包裹在它们中会将 primary-expression 转换为另一个 primary-expression ,即它几乎没有任何作用。

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

它是安全的,至少在没有意外操作员优先级后果方面。

任何只是没有操作员的简单字面的宏定义始终是安全的。例如...

#define FOO 1
#define NAME "Fred"
#define malloc my_malloc