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

时间:2011-12-30 07:58:21

标签: c++ linux unix macros history

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

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;符号,所以我猜有一个向后兼容的问题......

那么,unixlinux宏来自哪里?

1 个答案:

答案 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