今天我偶然发现了一个相当有趣的编译器错误:
int main() {
int const unix = 0; // error-line
return unix;
}
使用gcc 4.3.2(是的,古老的......)给出以下消息:
error: expected unqualified-id before numeric constant
这绝对令人困惑。
幸运的是,clang(3.0)更有帮助(像往常一样):
error: expected unqualified-id
int const unix = 0
^
<built-in>:127:14: note: expanded from:
#define unix 1
^
我当然没想到unix
,它既不是用大写字母写的,也不是用下划线作为宏,特别是内置的。
我检查了gcc中的预定义宏,并且有2个(在我的平台上)使用&#34; unreserved&#34;符号:
$ g++ -E -dM - < /dev/null | grep -v _
#define unix 1
#define linux 1
所有其他人都表现良好&#34;带有前导下划线的宏,使用传统的保留标识符,示例:
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define __unix__ 1
#define __unix 1
#define __CHAR_BIT__ 8
#define __x86_64 1
#define __amd64 1
#define _LP64 1
(这是一团糟,似乎没有任何特定的顺序......)
此外,还有很多类似的&#34;符号,所以我猜有一个向后兼容的问题......
那么,unix
和linux
宏来自哪里?
答案 0 :(得分:19)
默认情况下,gcc并不完全符合任何C标准。
使用-ansi
,-std=c99
或-std=c1x
调用它,unix
将无法预定义。 (<{1}} 可能会在成为 future 更近期的gcc版本中变为-std=c1x
。)
这有点令人困惑,这在GNU预处理器的单独手册中有记录,而不是在gcc手册中。
引用GNU预处理器文档(-std=c11
,版本4.5):
C标准要求所有特定于系统的宏都是其中的一部分 “保留命名空间”。所有以两个下划线开头的名称, 或者下划线和大写字母,保留给编译器 和库可以按照自己的意愿使用。但是,历史上 系统特定的宏具有没有特殊前缀的名称;对于 例如,在Unix系统上定义`unix'是很常见的。对于 所有这些宏,GCC提供了一个带有两个下划线的并行宏 在开始和结束时添加。如果定义了'unix', `__unix__'也将被定义。永远不会超过两个 下划线; `_mips'的并行是'__mips __'。
当`-ansi'选项或任何请求严格的`-std'选项时 符合性,给予编译器,所有系统特定的 保留命名空间外的预定义宏被抑制。该 保留命名空间内的并行宏仍然是定义的。
我们正在逐步淘汰所有预定义的宏 保留命名空间你永远不应该在新程序中使用它们,我们 鼓励您更正旧代码以使用并行宏 每当你找到它。我们不建议您使用特定于系统的 也可以是保留命名空间中的宏。它更好 从长远来看,使用工具专门检查您需要的功能 例如`autoconf'。
本手册的当前版本为here。