'true' 和 'false' 在预处理器条件中有它们通常的含义吗?

Do 'true' and 'false' have their usual meaning in preprocessor conditionals?

给定一个 C++11 编译器,#error 哪个是正确的编译器?

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

Godbolt demo

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

我问是因为似乎我尝试过的所有编译器都将其视为 'true',而静态代码分析工具坚持认为 true 未定义,隐式错误并最终出现在“这是假的”。

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

然而,在 C 中,truefalse 都不是关键字。从 C99 开始,它们是分别定义为 10 的宏 #include <stdbool.h>。这个 does 意味着,但是,如果你不包含 stdbool.h,编译器应该抱怨 truefalse 等的无法识别的标识符。之后包括 header,#if SOMEMACRO 现在是 #if 1,这在 C.

中是真实的

对于预处理,CppReference 中的这句话是有意义的:

Any identifier, which is not literal, non defined using #define directive, evaluates to 0.

因此在您的(可能是 C-oriented)静态分析工具中,它将 true 视为非 #define 定义的标识符,因此将 true 评估为零.如果您使用 C++ 分析工具,您将不会观察到这种行为。

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

根据the C++11 standard中的[cpp.cond]/4:

Prior to evaluation, macro invocations in the list of preprocessing tokens that will become the controlling constant expression are replaced (except for those macro names modified by the defined unary operator), just as in normal text. […] After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers and keywords, except for true and false, are replaced with the pp-number 0, and then each preprocessing token is converted into a token. The resulting tokens comprise the controlling constant expression which is evaluated according to the rules of [expr.const] using arithmetic that has at least the ranges specified in [support.limits]. […] Each subexpression with type bool is subjected to integral promotion before processing continues.

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

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

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

正如其他答案已经正确指出的那样,truefalse 应该适用于 C++ 编译器。

OP:确实是SCA工具的配置问题。在 Helix 中,选项 -preproccppkeywords 表示“启用后,C++ 替代标记将被视为关键字”。对此负责。打开时,它的行为符合预期。 truefalse 在预处理过程中被识别。