我找到了一些宏名称和替换列表相同的预处理指令。例如,gcc。
提供了stdbool.h中的一些预处理指令#else /* __cplusplus */
/* Supporting <stdbool.h> in C++ is a GCC extension. */
#define _Bool bool
#define bool bool
#define false false
#define true true
#endif /* __cplusplus */
我不明白为什么程序员编写了这些预处理指令。它们没用,替换会浪费时间。我知道这不会导致无限递归。如何避免无限递归? C标准中的相关规定是什么?
答案 0 :(得分:5)
C ++ 11标准第16.3.4节第2段:
阻止了宏替换期间的无限递归如果在替换列表的扫描期间找到要替换的宏的名称(不包括 其余的源文件的预处理令牌),它没有被替换。此外,如果有任何嵌套替换 遇到被替换的宏的名称,它不会被替换。这些未替换的宏名称预处理令牌不再可用于进一步替换,即使它们稍后(重新)检查在上下文中 否则,宏名称预处理令牌将被替换。
基本上,这意味着在自己的扩展中出现的宏不会再被替换。
GCC扩展名将true
,bool
和false
定义为宏的原因是为了使C ++代码与C99更兼容。在C99中,这些被定义为stdbool.h中的宏,因此代码可以检查它们是否使用例如#ifdef bool
。
答案 1 :(得分:2)
除了其他答案之外,定义这些宏将有助于编译器生成“宏重新定义”错误消息,如果任何人,任何地方都有重新定义bool的真实想法,无论是真还是假。
参见标准第16.3节 - 在宏重新定义中只允许相同的替换列表。
答案 2 :(得分:1)
有时标准说“X
必须是宏。”如果您的语言已有内在X
,则必须说#define X X
符合标准。 (例如,用户可以说#ifdef X
并期望这是真的。)
示例(C11,7.2 / 2):
assert
宏应实现为宏,而不是实际功能。如果 为了访问实际函数,宏定义被抑制,行为是 未定义。
您的实施完全有合理的assert
功能。
为了好玩,以下是一些“未指定”的东西,它们是宏还是带有外部链接的标识符:
errno
setjmp
va_copy
,va_end
putc
,getc
答案 3 :(得分:1)
宏扩展不会递归,因此它们将终止。
拥有宏的一个优点是您可以在预处理器中对其进行测试
#if defined bool
...
#endif
仅在bool
为宏时才有效。