将无保留标识符作为gcc中的内置宏的原因是什么?

Mat*_* M. 25 c++ unix linux macros history

今天我偶然发现了一个相当有趣的编译器错误:

int main() {
  int const unix = 0; // error-line
  return unix;
}
Run Code Online (Sandbox Code Playgroud)

使用gcc 4.3.2给出以下消息(是的,古老的......):

error: expected unqualified-id before numeric constant
Run Code Online (Sandbox Code Playgroud)

这绝对是令人困惑的.

幸运的是,clang(3.0)更有帮助(像往常一样):

error: expected unqualified-id
  int const unix = 0
            ^
<built-in>:127:14: note: expanded from:
#define unix 1
             ^
Run Code Online (Sandbox Code Playgroud)

我当然没想到unix,既不是用大写字母写的,也不是用下划线作为宏,特别是内置的宏.

我检查了gcc中的预定义宏,并且有2个(在我的平台上)使用"未保留"符号:

$ g++ -E -dM - < /dev/null | grep -v _
#define unix 1
#define linux 1
Run Code Online (Sandbox Code Playgroud)

所有其他的都是具有前导下划线的"表现良好"的宏,使用传统的保留标识符,示例:

#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
Run Code Online (Sandbox Code Playgroud)

(这是一团糟,似乎没有任何特定的顺序...)

此外,有很多"相似"的符号,所以我想有一个向后兼容的问题......

那么,宏unixlinux宏从何而来?

Kei*_*son 19

默认情况下,gcc不完全符合任何C标准.

与调用它-ansi,-std=c99-std=c1xunix不会被预定义.(-std=c1x 可能会成为成为-std=c11未来更近的gcc版本.)

这有点令人困惑,这是在GNU预处理器的单独手册中记录的,而不是在gcc手册中.

引用GNU预处理器文档(info cpp,版本4.5):

C标准要求所有特定于系统的宏都是"保留命名空间"的一部分.所有以两个下划线或下划线和大写字母开头的名称都保留给编译器和库以供其使用.但是,历史上系统特定的宏具有没有特殊前缀的名称; 例如,在Unix系统上定义`unix'是很常见的.对于所有这些宏,GCC提供了一个并行宏,在开头和结尾添加了两个下划线.如果定义了`unix',那么也将定义`__ixix__'.永远不会超过两个下划线; `_mips'的并行是`__mips__'.

当`-ansi'选项或任何请求严格一致性的`-std'选项被赋予编译器时,保留命名空间之外的所有系统特定的预定义宏都被抑制.保留命名空间内的并行宏仍然是定义的.

我们正在逐步淘汰保留命名空间之外的所有预定义宏.您永远不应该在新程序中使用它们,我们建议您更正旧代码,以便在找到它时使用并行宏.我们不建议您使用保留命名空间中的系统特定宏.从长远来看,使用诸如`autoconf'之类的工具来检查您需要的功能会更好.

当前版本的手册在这里.