预处理器#if中逻辑与(&&)未正确短路的跨编译器行为疑问
预处理器#if中逻辑与(&&)未正确短路的跨编译器行为疑问
各位好,最近碰到一个挺有意思的跨编译器差异问题,关于C预处理器#if里&&的短路行为,跟大家聊聊。
先看这段测试代码:
#if defined(FOO) && FOO(foo) #error "FOO is defined." #else #error "FOO is not defined." #endif
这段代码的预期逻辑应该是:如果FOO被定义,才去求值FOO(foo),否则直接走#else分支——毕竟&&应该有短路特性对吧?但不同编译器的处理结果完全不一样:
MSVC 19.38的输出
<source>(1): warning C4067: unexpected tokens following preprocessor directive - expected a newline <source>(4): fatal error C1189: #error: "FOO is not defined."
MSVC这里只给了个警告,然后正常走到了#else分支,抛出对应的#error。
ICX 2024.0.0 和 Clang 18.1的输出
<source>:1:21: error: function-like macro 'FOO' is not defined 1 | #if defined(FOO) && FOO(foo) | ^ <source>:4:6: error: "FOO is not defined." 4 | #error "FOO is not defined." | ^ 2 errors generated.
这俩编译器直接报错,说函数式宏FOO未定义,说明它们没有短路&&右边的表达式,直接去解析了FOO(foo)。
GCC 14.1的输出
<source>:1:24: error: missing binary operator before token "(" 1 | #if defined(FOO) && FOO(foo) | ^ <source>:4:6: error: "FOO is not defined."
GCC则报了语法错误,同样是因为尝试解析FOO(foo)时发现FOO不是宏,导致表达式不合法。
按C标准的话,#if中的逻辑表达式应该遵循短路求值:当defined(FOO)为假时,右边的FOO(foo)不应该被求值。但从实际编译结果来看,不同厂商的编译器在预处理器阶段的实现差异还挺大的,这确实是个容易踩坑的细节。
备注:内容来源于stack exchange,提问作者Madagascar
相关产品推荐
相关产品推荐

