在我目前的代码库中,我看到以下模式:
#if SOMETHING_SUPPORTED+0 != 0
...
#endif
不幸的是,这是一个非常古老的代码库,没有人知道它是如何以及为什么开始的。我认为它是从C开始的,它慢慢地转换为C类,现在它倾向于C ++
我看不到使用先前构造而不是“经典”的明显优势,但也许我错过了一些东西:
#if SOMETHING_SUPPORTED
...
#endif
您知道为什么会使用#if MACRO+0 != 0
代替#if MACRO
吗?
答案 0 :(得分:71)
这里的线索是代码库非常陈旧。
这个技巧可能存在,因为代码曾经被一些非常旧的预处理器移植到编译器,而预处理器中的未定义的宏在预处理器#if
条件中不会被视为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
技巧很整洁,并且重视其自我控制。
答案 1 :(得分:44)
#if X+0 != 0
被定义为空的情况下, #if X
与X
不同(注意:这与X
未定义的情况不同),例如:
#define X
#if X // error
#if X+0 != 0 // no error; test fails
定义空宏非常常见:项目配置可能会生成一些包含一堆行#define USE_FOO
,#define USE_BAR
的公共标题,以启用系统支持的功能,等等。
!= 0
是多余的,代码可能只是#if X+0
。
因此,使用#if X+0
的好处是,如果将X
定义为空,则继续编译,跳过该块,而不是触发错误。
这是否是一个好主意是值得商榷的,我个人会将#ifdef
用于布局宏(如USE_SOME_FEATURE
)和#if
用于宏,其值可能是整数范围,例如;如果我不小心将#if
与定义为空的东西一起使用,我希望看到一个错误。
答案 2 :(得分:35)
让我们做一张桌子!
X #if X #if X+0 != 0
<undef> false false
<empty> error false
0 false false
1 true true
2 true true
a false false
xyz false false
12a error error
12 a error error
因此我们发现的唯一区别(感谢评论者)是定义了X但没有值的情况(如空字符串)。我之前从未见过+0 != 0
变体。
答案 3 :(得分:7)
这是另一种写作方式
#if defined(MACRO) && MACRO != 0
+0用于确保结果为数字。如果未定义MACRO
,则会避免#if MACRO != 0
导致的语法错误。
质量差的东西,但除非得到,否则不要惹它。