c++ 为什么没有undef的宏重定义会导致格式不正确的程序

xesrikrc  于 11个月前  发布在  其他
关注(0)|答案(3)|浏览(88)

根据standard宏的重新定义,在以下情况下禁止使用#undef
但以下重新定义无效:

#define OBJ_LIKE    (0)         // different token sequence
#define OBJ_LIKE    (1 - 1)     // different whitespace

字符串
同时,对于之前根本没有定义的宏,允许使用#undef
如果指定的标识符当前未定义为宏名,则将忽略该标识符。
我感兴趣的是这样做的理由是什么,即禁止在中间没有#undef的情况下重新定义?一些编译器优化的目的还是什么?

0sgqnhkj

0sgqnhkj1#

这是不允许的,因为默默地重新定义一个宏来表示其他东西可能是一个错误。考虑下面的例子:

// in assertions.hpp
#define assert(expr, msg) if (!expr) std::cout << msg << '\n';

个字符
这个Assert现在成功了,因为<cassert>中的assert重新定义了Assert是什么。一般来说,重新定义事物可能会产生一些后果:

  • 简单地产生编译器错误
  • 静默重定义全局常量以具有不同的值
  • 静默地重新定义类似于函数的宏以具有不同的行为

请记住,#include的顺序很重要,每个宏都可以通过这种方式溢出到任何其他头中。与宏重新定义相关的错误可能很难跟踪。
如果你想改变一个宏名的用途,你可以先#undef它。

yzxexxkh

yzxexxkh2#

因为它继承自C。
ISO/IEC 9899:1990 §6.8.3(AKA C90)包含类似措辞:
如果第二个定义是一个类似于对象的宏定义,并且两个替换列表是相同的,那么当前定义为一个没有使用lparen的宏(类似于对象的宏)的标识符可以由另一个#define预处理指令重新定义。
当前使用lparen定义为宏的标识符(类似 * 函数的 * 宏)可以由另一个#define预处理指令重新定义,只要第二个定义是类似函数的宏定义,具有相同的参数数量和拼写,并且两个替换列表相同。
再看看WG 14(https://www.open-std.org/jtc1/sc22/wg14/www/docs/n802.pdf)《国际标准-程序设计语言- C的基本原理》§6.8.3产生的N802,理由是:
委员会希望不允许“有害的重新定义”,
(in header1.h)

#define NBUFS 10

字符串
(in header. h)

#define NBUFS 12


这显然是程序中严重错误的诱因。然而,仍然存在“良性重新定义”的问题,例如(在header1.h中)

#define NULL_DEV 0


(in header. h)

#define NULL_DEV 0


委员会得出结论认为,在定义相同的情况下,允许良性重定义可以更好地服务于安全编程实践。这允许独立的标头指定他们对每个感兴趣的符号的正确值的理解,只有在定义不同时才会生成诊断。
因此,鼓励“良性”的重新定义,替代方案可能是这样的:

#ifdef SPEED_OF_LIGHT
#if SPEED_OF_LIGHT != 299792458
#error Some other header defines SOME_UNIVERSAL_CONSTANT wrong
#endif
#else
#define SPEED_OF_LIGHT 299792458
#endif


#define SPEED_OF_LIGHT 299792458会在另一个header以不同的方式定义它时生成一个警告。
#undef也是类似的情况。第6.8.3.5节给出的理由是:
它明确允许#undef一个没有当前定义的宏。这个功能可以和标准库一起使用(见§7.1.8)。
其中C99的§7.1.8/C90的§7.1.7规定:
使用#undef删除任何宏定义也将确保引用实际函数。
例如,一个标准的库头可能有double abs(double);#define abs(x) _BUILTIN_abs(x),而#undef abs是法律的,允许您确保abs引用真正的函数。
当然,这并不适用于C++,在C++中标准库函数不能是宏。但另一个理由(“明确允许#undef一个没有当前定义的宏”)仍然适用,即“委员会是这么说的”。

zf9nrax1

zf9nrax13#

我们不能检查MACRO定义,我们只能检查是否定义了MACRO。
所以,如果你想检查#undef只在定义的MACRO上完成,你可以自己检查:

#ifdef MY_MACRO
# undef MY_MACRO
#else
# error "Expected previous definition"
#end

字符串
对于重新定义宏观,

#define MY_MACRO some_def

// #ifdef MY_MACRO // only check it is defined not its definition
                   // so cannot differentiate for below two cases

#define MY_MACRO some_def    // OK (same def)
#define MY_MACRO another_def // Invalid

相关问题