在#define 之前使用#undef

Using #undef before #define

在很多地方我看到在定义同一个宏之前使用 undefine 宏。例如:

#undef FORMULA
#ifdef SOMETHING
#define FORMULA 1
#else 
#define FORMULA 2
#endif

#undefine FORMULA用的是什么? 我可能猜想它处理的是宏之前已经定义过的情况。但是新定义不是覆盖了旧定义吗?谢谢!

But isn't the new definition overrides the old one?

是的,确实如此(当您的编译器允许时)。但是,重新定义宏会导致编译器警告,使用 #undefine 可以避免这种情况。

这在对编译器警告有严格规定的编程工作室中可能很重要 - 例如,要求所有生产代码都使用 -Werror 标志进行编译,该标志将所有警告视为错误。

是的,新定义覆盖所有以前的定义。但是有相应的警告信息。 #undef 你没有警告。

#undef 删除了宏,所以名称可以重新定义。

如果宏一开始就没有定义,#undef 就没有效果,所以没有缺点。 #undef#define 应理解为替换任何可能的先前定义,但并不意味着它必须已经被定义。

流行的编译器确实允许您跳过 #undef,但官方标准 ISO C 和 C++ 语言规范不允许这样做。这样做是不可移植的。

当前定义的宏名不能用不同的定义重新定义(见下文),因此#undef允许用不同的定义重新定义宏名。

这里是相关的法律术语:

C 和 C++ 标准(相同的措辞):

A macro definition lasts (independent of block structure) until a corresponding #undef directive is encountered or (if none is encountered) until the end of the preprocessing translation unit.

措辞略有不同,意思相同:

C Standard (N1256), §6.10.3/2:
An identifier currently defined as an object-like macro shall not be redefined by another #define preprocessing directive unless the second definition is an object-like macro definition and the two replacement lists are identical. Likewise, an identifier currently defined as a function-like macro shall not be redefined by another #define preprocessing directive unless the second definition is a function-like macro definition that has the same number and spelling of parameters, and the two replacement lists are identical.

C++ Standard (N3337) §16.3/2
An identifier currently defined as an object-like macro may be redefined by another #define preprocessing directive provided that the second definition is an object-like macro definition and the two replacement lists are identical, otherwise the program is ill-formed. Likewise, an identifier currently defined as a function-like macro may be redefined by another #define preprocessing directive provided that the second definition is a function-like macro definition that has the same number and spelling of parameters, and the two replacement lists are identical, otherwise the program is ill-formed.

两个标准中的相同措辞:

Two replacement lists are identical if and only if the preprocessing tokens in both have the same number, ordering, spelling, and white-space separation, where all white-space separations are considered identical.

所以:

#define X(y)   (y+1)
#define X(z)   (z+1)   // ill-formed, not identical

恕我直言,由于预处理器宏的作用域规则,使用 #undef 通常是危险的。我宁愿从预处理器那里得到警告或错误并提出一个不同的预处理器宏,而不是让一些翻译单元默默地接受错误的宏定义,从而将错误引入程序。考虑:

// header1.h
#undef  PORT_TO_WRITE_TO
#define PORT_TO_WRITE_TO    0x400

// header2.h
#undef  PORT_TO_WRITE_TO
#define PORT_TO_WRITE_TO    0x410

并且有一个翻译单元 #include headers。没有警告,可能不是预期的结果。