“真”和“假”在预处理器条件中是否具有通常的含义?

给定一个 C++11 编译器,#error它最终应该使用哪个正确的编译器?

// no #includes!
#define SOMEMACRO true
#if SOMEMACRO
  #error "it was true"
#else
  #error "it was false"
#endif

Godbolt 演示

显然我#error只是作为测试使用。我知道truefalse以适当的语言定义,但这是预处理器上下文。在 C99 中,它似乎不被预处理器识别。

我问是因为似乎我尝试过的所有编译器都将其视为“真”,而静态代码分析工具坚持认为true未定义,隐含错误并以“它是假的”结束。

回答

在所有 ISO C++ 标准中,truefalse都是关键字常量,就像nullptr在 C++11 中一样。所以#if SOMEMACRO=#if true并且预处理器将转到真实分支。

然而,在 C 中,既不是关键字true也不false是关键字。它们是分别定义为1和 的宏0,从 C99 开始,带有#include <stdbool.h>. 这等于说但是,如果不包括stdbool.h,编译器应该抱怨无法识别的标识符truefalse等等,包括头之后,#if SOMEMACRO现在#if 1,这是truthy在C.

对于预处理,来自CppReference 的引用是有意义的:

任何不是文字的、非使用#define指令定义的标识符的计算结果为0

因此,在您的(可能是面向 C 的)静态分析工具中,它被true视为#define未定义的标识符,因此计算结果true为零。如果您使用 C++ 分析工具,您将不会观察到这种行为。

在这种情况下,您可能一开始就不应该错过#include <stdbool.h>

  • For reference, `true` and `false` are [specifically singled out](https://timsong-cpp.github.io/cppwp/n3337/cpp.cond#4) to not be replaced when other identifiers are replaced. `nullptr` is a literal, but it doesn't get this treatment, which you can see with a condition such as `#if nullptr + 2 == 2` that would fail to compile if `nullptr` were not replaced with `0`.

回答

根据C++11 标准中的[cpp.cond]/4 :

在评估之前,将成为控制常量表达式的预处理标记列表中的宏调用被替换(除了那些被defined一元运算符修改的宏名称),就像在普通文本中一样。[…] 由于宏扩展和defined一元运算符的所有替换都执行完毕后,trueand之外的false所有剩余标识符和关键字都替换为 pp-number 0,然后将每个预处理标记转换为一个标记。结果标记包括控制常量表达式,该表达式根据 [expr.const] 的规则使用至少具有 [support.limits] 中指定的范围的算术进行评估。[…] 每个带有类型的子表达式bool 在继续处理之前进行积分提升。

强调我的;从粗体段落可以看出,bool-typed 表达式旨在在预处理器条件中得到支持,就像在适当的语言中一样,包括bool文字truefalse. 定义常量表达式的 [expr.const] 部分是从在非预处理上下文中使用它的其他部分引用的,从这些部分可以看出,预处理器和语言本身中的评估规则是相同的。

我认为类似的语言出现在 C++ 标准的所有进一步修订版中,也可能出现在更早的版本中。另一方面,在 C 中,trueandfalse不是关键字,而是定义在 中的宏stdbool.h,因此预处理器将它们视为任何其他标记。

通常的做法是在预处理器表达式中使用10用于逻辑值以获得最大的可移植性,并且最好避免完全直接引用它们。


以上是“真”和“假”在预处理器条件中是否具有通常的含义?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>