【问题标题】:The subtle difference between #ifdef and #if for a macro defined as 0对于定义为 0 的宏,#ifdef 和 #if 之间的细微差别
【发布时间】:2014-01-23 15:32:54
【问题描述】:

给定下面的 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

下面的预期输出是什么?

$ 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 对于已定义的特性评估为真即使定义的值为 0(零)

另一个 C 预处理器陷阱!这是按照 C 标准应该是这样的吗?

【问题讨论】:

  • 我认为差异特别“微妙”,也不是任何形式的“陷阱”。这对我来说似乎相当清晰和直观。 #ifdef 代表“如果已定义”。为什么你认为那里的价值与它有任何关系?也许来自 PHP/Javascript 的惰性比较?
  • 将宏定义为具有 0fred"" 或其他任何值,实际上仍在定义该宏,因此在我看来 #ifdef 应该报告宏已定义(如果已定义) - 它不关心定义的值是什么,只关心它已定义...
  • 您的问题可以通过阅读标准来回答;你为什么要让其他人为你读它?

标签: c macros c-preprocessor


【解决方案1】:

为了评估#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

如果FOO 未定义,则计算结果为1,因为它将被视为0,然后!FOO 将被计算为!0,即1

【讨论】:

    【解决方案2】:

    #ifdef 只关心 MACRO 是否已定义。价值无关紧要。

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

    这是正确的行为

    【讨论】:

    • 这并没有回答如何在#if 语句的表达式中评估未定义标识符的问题。
    • 这在 C 和 C++ 标准中明确定义 - 不是 #define'd 作为宏的标识符在 #if 或 #elif 语句中被替换为 0。这应该是常识。
    • 我可以确认#if在未定义符号时的行为与使用0值定义时的行为相同。
    【解决方案3】:

    行为符合标准。

    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 definedidentifier#if !definedidentifier 分别。

    【讨论】:

    • 这并没有回答如何在#if 语句的表达式中评估未定义标识符的问题。
    • 阅读上面的答案,或 C 标准。 Google for N1570 下载该标准的最新免费草案。
    • 但是我们可以使用#ifdef#elif。如果我们 #define 宏的值为 0#ifdef 案例,#ifdef 案例测试它为真。否则,如果我们将 #define 宏的值 0 用于 #elif 案例,则 #elif 案例将其测试为 false
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-28
    • 2011-04-26
    • 1970-01-01
    • 2010-11-04
    • 1970-01-01
    • 1970-01-01
    • 2013-06-22
    相关资源
    最近更新 更多