这个无括号的C预处理器定义是否安全
Is this parenthesis-free C preprocessor definition safe?
在我的 /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
- 错误:无效的预处理指令 #i 的意思是 #if?
- C++预处理会生成变量成员、资源库和映射
- 使用预处理指令检查是否包含标头?
- 预处理的 C/C++ 文件是否特定于计算机?
- 使用 GCC 对 C 文件进行部分预处理(不删除 "define" 指令)
- 在 CPLEX 中求解线性规划,无需剪切和预处理
- CPP -D 选项,用于预处理 Fortran 代码
- 错误:粘贴"tmp_UINT"和"+"未提供有效的预处理令牌
- 任务计划程序库的预处理不起作用 - 多定义错误
- Eclipse 问题 - 编译期间不考虑 .c 和 .cpp 文件中定义的预处理
- 使用python预处理后,C++(opencv)中的垫子类型数据与image_to_array相同
- Howo 使用 cl 预处理为 masm 组装生成一个单独的文件
- 我有一个预处理的 C/C++ 源文件 (cacti.i).如何从这个 .i 文件生成可执行二进制文件,以便我可以像 ./
- 如何使用Visual Studio C/C++编译器(cl.exe)来预处理我的objective-C代码
- 是具有预处理前分支实现的结构违反ODR
- 与不完整的Cholesky预处理的共轭梯度返回特征库的意外错误
- Visual Studio C - 无法输出预处理文件
- 在海湾合作委员会中加快宏观预处理的任何方法
- 所有结构成员的预处理器批处理
- 当头文件被预处理时是否有一个预处理器选项显示?