对于定义为0的宏,#ifdef和#if之间的细微差别

vap*_*ace 6 c macros c-preprocessor

给出下面的C文件:

$ cat macros.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
Run Code Online (Sandbox Code Playgroud)

以下的预期产量是多少?

$ gcc           -c macros.c
$ gcc -DMACRO   -c macros.c
$ gcc -DMACRO=0 -c macros.c
Run Code Online (Sandbox Code Playgroud)

:这是我机器上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
$
Run Code Online (Sandbox Code Playgroud)

课程:即使定义的值为0(零),也会#ifdef MACRO对定义的内容求值为true .

另一个C预处理器了!这是按照C标准应该如何吗?

Ada*_*eld 7

为了评估#if语句的控制表达式,任何未定义的宏都被视为定义为0 .从C99§6.10.1/ 3-4(重点补充):

3)表格的预处理指令

# if constant-expression new-line groupopt
# elif constant-expression new-line groupopt

检查控制常量表达式是否计算为非零.

4)在评估之前,将替换将成为控制常量表达式的预处理标记列表中的宏调用(除了由defined一元运算符修改的那些宏名称之外),就像在普通文本中一样.如果defined由于此替换过程而生成令牌,或者defined在宏替换之前使用一元运算符与两个指定表单中的一个不匹配,则行为是未定义的.在由于宏扩展和defined一元运算符执行的所有替换之后,所有剩余的标识符(包括与关键字词法相同的标识符)被替换为pp-number 0,然后每个预处理标记被转换为标记.[...]

所以,例如,像这样的表达式:

#if !FOO
Run Code Online (Sandbox Code Playgroud)

将评估1if FOO是否未定义,因为它将被视为0,然后!FOO将被评估为!0,即1.


小智 5

#ifdef 只关注MACRO是否已被定义.价值无关紧要.

#if 检查MACRO的值并相应地评估MACRO.

这是正确的行为

  • 这没有回答如何在`#if`语句的表达式中计算未定义标识符的问题. (2认同)
  • 这在 C 和 C++ 标准中明确定义 - 在 #if 或 #elif 语句中,未#define 为宏的标识符将替换为 0。这应该是常识。 (2认同)

Alo*_*ave 2

行为符合标准。

C99标准: 6.10.1 有条件包含:

第 2 段:表单的预处理指令

# if constant-expression new-line groupopt
# elif constant-expression new-line groupopt
Run Code Online (Sandbox Code Playgroud)

检查控制常量表达式的计算结果是否为非零。

第 4 段:表单的预处理指令

# ifdef identifier new-line groupopt
# ifndef identifier new-line groupopt
Run Code Online (Sandbox Code Playgroud)

检查标识符当前是否定义为宏名称。它们的条件分别相当于#if defined 标识符#if !defined 标识符

  • 这并没有回答如何在“#if”语句中的表达式中计算未定义标识符的问题。 (2认同)