这里的线索是代码库很旧。
这个技巧可能存在,因为代码曾经被移植到带有一些非常旧的预处理器的编译器,该预处理器不会在预处理器#if 条件中将 undefined 宏视为 0。
也就是说,从 1989 年 ANSI C 开始,如果我们有:
#if foo + bar - xyzzy
指令会被宏替换,因此如果foo、bar 或xyzzy 是宏,它们会被替换。然后任何未替换的剩余标识符将替换为0。所以如果foo被定义为42,但bar和xyzzy根本没有定义,我们得到:
#if 42 + 0 - 0
并不是说语法不好:
#if 42 + -
或其他一些行为,例如关于未定义 bar 的诊断。
在未定义的宏被视为空白的预处理器上,#if SOMETHING_SUPPORTED 仅扩展为 #if,这是错误的。
这是IDENT+0 技巧真正有意义的唯一方法。如果您可以依赖符合 ISO C 的预处理,您根本就不会想要这样做。
原因是,如果 SOMETHING_SUPPORTED 预期具有数值,那么将其定义为简单的空白是错误的分散思维。理想情况下,您希望检测何时发生这种情况并通过诊断停止编译。
其次,如果您确实支持这种分散注意力的用法,那么您几乎肯定希望明确定义但空白符号的行为就好像它具有值 1,而不是值 0。否则,你正在制造一个陷阱。有人可能会在编译器命令行上这样做:
-DSOMETHING_SUPPORTED=$SHELL_VAR # oops, SHELL_VAR expanded to nothing
或在代码中:
#define SOMETHING_SUPPORTED /* oops, forgot "1" */
没有人会添加 #define 或 -D 符号以关闭它控制的功能!插入#define SOMETHING_SUPPORTED 而没有1 的程序员会对
#if SOMETHING_SUPPORTED+0
它会跳过打算启用的材料。
这就是为什么我怀疑阅读本文的 C 程序员很少见过这种用法,以及为什么我怀疑这只是预处理器行为的一种解决方法,其预期效果是在缺少 SOMETHING_SUPPORTED 时跳过该块。它设置“程序员陷阱”的事实只是解决方法的副作用。
要在不造成程序员陷阱的情况下解决这样的预处理器问题,需要在翻译单元的早期某处拥有:
#ifndef SOMETHING_SUPPORTED
#define SOMETHING_SUPPORTED 0
#endif
然后在其他地方使用#if SOMETHING_SUPPORTED。可能最初的程序员没有想到这种方法,或者可能那个程序员认为+0 的技巧很巧妙,并重视它的自包含。