【问题标题】:Can I redefine a macro with another #define directive?我可以用另一个#define 指令重新定义宏吗?
【发布时间】:2020-06-22 10:34:28
【问题描述】:

我想用另一个值重新定义一个宏常量的值。现在我知道了使用#undef 并随后重新使用#define 宏本身的技术,例如:

#define LEN_OSG 59
....
#undef LEN_OSG
#define LEN_OSG 70

我尝试将其缩写并发现可能通过另一个 #define 指令重新定义宏常量:

#define LEN_OSG 59
....
#define LEN_OSG 70

Example program:

#include <stdio.h>

#define LEN_OSG 59

int main()
{

    printf("LEN_OSG is %d.\n",LEN_OSG);

    #define LEN_OSG 70

    printf("LEN_OSG is %d.",LEN_OSG);
}

当然,gcc 和 clang 都会给我警告:

警告:“LEN_OSG”重新定义。 (gcc)

警告:“LEN_OSG”宏已重新定义 [-Wmacro-redefined] (clang)

但他们确实编译它(当然没有-Werror 选项)并给出正确的结果:

Execution build compiler returned: 0
Program returned: 0
LEN_OSG is 59.
LEN_OSG is 70.

我的问题:

  • 我可以通过忽略此特定警告,使用另一个 #define 指令重新定义宏吗?
  • 这是否涉及未定义的行为或对程序造成潜在损害?

非常感谢。

【问题讨论】:

  • 你可以仔细看看#undef
  • @Gerhardh 我应该特别关注#undef 哪里?我不明白。
  • 您收到警告,因为宏已定义。现在您有了一个预处理器指令,它使宏不再被定义。对我来说似乎是一个完美的匹配。
  • 不要试图搞乱预处理器指令,而是写一个新问题来解释你试图实现的更大目标并询问如何实现它。

标签: c macros language-lawyer c-preprocessor preprocessor-directive


【解决方案1】:

在重新定义宏之前,你真的应该习惯使用#undef!大多数编译器都会产生警告;但是,根据C99 Standard(以及C18 Standard - 两者的段落相同):

6.10.3 宏替换
...
2 当前定义为类对象宏的标识符不应由另一个#define 预处理指令重新定义,除非第二个定义是类对象宏定义并且两个替换列表相同。同样,当前定义为类函数宏的标识符不应由另一个#define 预处理指令重新定义,除非第二个定义是具有相同数量和参数拼写的类函数宏定义,并且两个替换列表相同.

您示例中LEN_OSG(类对象)宏的“替换列表”是59,然后是70——它们相同。

【讨论】:

    【解决方案2】:

    重新定义宏(当重新定义不相同时)是违反约束。约束在C standard 的 sectino 6.10.3p2 中有详细说明:

    当前定义为类对象宏的标识符应 不会被另一个 #define 预处理指令重新定义,除非 第二个定义是一个类似对象的宏定义和 这两个替换列表是相同的。 同样,一个 当前定义为类函数宏的标识符应 不会被另一个 #define 预处理指令重新定义 除非第二个定义是类似函数的宏 具有相同数量和拼写参数的定义, 并且两个替换列表是相同的。

    第 4p2 节规定了以下关于违反约束的规定:

    如果“应”或“不应”要求出现在外部 违反了约束或运行时约束,则 行为未定义。 未定义的行为以其他方式指示 在本国际标准中用“未定义 行为”或省略任何明确的定义 行为。这三者在重点上没有区别;他们 都描述了“未定义的行为”。

    所以重新定义宏会调用undefined behavior。如果您想重新定义宏,您必须使用#undef

    【讨论】:

      猜你喜欢
      • 2012-09-11
      • 2010-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 2015-04-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多