给出下面的 C 文件:
#ifdef MACRO
# error MACRO is defined
#else
# error MACRO is undefined
#endif
#if MACRO
# error MACRO is non-zero
#else
# error MACRO is zero
#endif
以下的预期输出是什么?
gcc -c macros.c
gcc -DMACRO -c macros.c
gcc -DMACRO=0 -c macros.c
答案:这是我机器上的 gcc 预处理器的作用。
gcc -c macros.c
输出:
macros.c:4:4: error: #error MACRO is undefined
macros.c:9:4: error: #error MACRO is zero
并且:
gcc -DMACRO -c macros.c
输出:
macros.c:2:4: error: #error MACRO is defined
macros.c:7:4: error: #error MACRO is non-zero
并且:
gcc -DMACRO=0 -c macros.c
输出:
macros.c:2:4: error: #error MACRO is defined
macros.c:9:4: error: #error MACRO is zero
课程:
#ifdef MACRO
对于定义性计算结果为 true 即使定义值为 0(零)。
这是另一个 C 预处理器陷阱!按照 C 标准,这应该是这样吗?
为了评估
#if
语句的控制表达式,任何未定义的宏都将被视为定义为 0。来自 C99 §6.10.1/3-4(添加强调):
3)表单的预处理指令
# if constant-expression new-line group
opt
# elif constant-expression new-line group
opt
检查控制常量表达式的计算结果是否为非零。
4) 在评估之前,预处理标记列表中的宏调用将成为 控制常量表达式被替换(修改的宏名称除外) 由
一元运算符),就像在普通文本中一样。如果令牌defined
是 由于此替换过程或使用defined
一元运算符而生成 与宏替换之前的两个指定形式之一不匹配,行为是 不明确的。 由于宏展开和defined
一元进行所有替换之后 运算符已执行,所有剩余的标识符(包括词法上的标识符) 与关键字相同)替换为 pp-number 0,然后每次预处理 令牌被转换为令牌。 [...]defined
因此,例如,这样的表达式:
#if !FOO
如果
1
未定义,则计算为 FOO
,因为它将被视为 0,然后 !FOO
将计算为 !0
,即 1
。
#ifdef
只关心MACRO是否已定义。价值并不重要。
#if
检查 MACRO 的值并相应地评估 MACRO。
这是正确的行为
行为符合标准。
C99标准:6.10.1 有条件包含:
第 2 段:表单的预处理指令
# if constant-expression new-line groupopt
# elif constant-expression new-line groupopt
检查控制常量表达式的计算结果是否为非零。
第 4 段:表单的预处理指令
# ifdef identifier new-line groupopt
# ifndef identifier new-line groupopt
检查标识符当前是否定义为宏名称。他们的 条件相当于
#if defined
identifier 和 #if !defined
identifier
分别。