c - 为什么C 预处理器把word "linux"解释为常量"1"?

  显示原文与译文双语对照的内容

为什么GCC中的C 预处理器将单词 linux ( 小写字母) 解释为常量 1

test.c:


#include <stdio.h>
int main(void)
{ 
 int linux = 5;
 return 0;
}

结果 $ gcc -E test.c ( 预处理阶段后停止):


....
int main(void)
{
 int 1 = 5;
 return 0;
}

哪个 -of course-产生错误。

(顺便说一句:没有 #define linux stdio.h 文件。)

时间:

在旧社会( pre-ANSI ) 预定义的符号,如 unixvax 是一种允许代码在编译时检测系统被编译。 当时没有官方的语言标准,( 超出 k& R 第一版的参考材料),任何复杂的C 代码都是 #ifdef的复杂迷宫,允许系统之间的差异。 这些宏定义通常由编译器本身设置,而不是在库头文件中定义。 因为没有真正的规则,实现和使用的标识符可以预留给程序员,编译器作者免费使用简单的名字像是 unix 和假定程序员只会避免使用那些名称为自己的目的。

1989 ANSI标准引入了限制实现的符号合法预定义的规则。 由编译器预定义的宏只能有一个以两个下划线开头的名称,或者一个下划线,后面紧跟一个大写字母,使程序员可以自由使用不匹配该模式的标识符,也不在标准库中使用。

因此,任何预先定义 unix 或者 linux的编译器都是 non-conforming,因为它将无法编译使用类似 int linux = 5;

在默认情况下,gcc是non-conforming默认为 --,但它可以使( 合理地井好) 与正确的command-line选项一致:


gcc -std=c90 -pedantic.. . # or -std=c89 or -ansi
gcc -std=c99 -pedantic
gcc -std=c11 -pedantic

有关更多详细信息,请参阅手册

gcc将在未来的版本中逐步淘汰这些定义,所以你不应该编写依赖于它们的代码。 如果你的程序需要知道是否正在为一个Linux目标编译它,它可以检查 __linux__ 是否被定义为( 假设你正在使用gcc或者与它兼容的编译器) 。 有关更多信息,请参阅预处理器手册。

一个很不相关的方面:1987 国际模糊C 代码竞赛的"最好的一个衬垫"赢家,David Korn ( 是的,Korn Shell的作者) 利用了预定义的unix 宏:


main() { printf(&unix["21%six12"],(unix)["have"]+"fun"-0x60);}

它打印 "unix",但由于它与宏名称的拼写毫无关系。

这似乎是一个( 未记录文档)"gnu扩展": [ 校正:我终于找到一个提到的文档。 见下面。]

以下命令使用 -dM 选项打印所有预处理器;因为输入"文件"为空,它完全显示预定义的宏。 它是用 gcc-4.7.3 在一个标准的ubuntu安装上运行的。 你可以看到预处理器是 standard-aware 。 总共有 243个带有 -std=gnu99 和 240的宏;我过滤了输出的相关性。


$ cpp --std=c89 -dM </dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1

$ cpp --std=gnu89 -dM </dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1

$ cpp --std=c99 -dM </dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1

$ cpp --std=gnu99 -dM </dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1

"gnu标准"版本也 #define unix 。 ( 使用 c11gnu11 产生相同的结果。)

我想他们的原因,但是在我看来默认安装的gcc( 除非另行指定,否则使用 -std=gnu89 编译C 代码) non-conformant,和 -- --奇怪这个问题。 不允许以下划线开头的全局命名空间( 它的名称不以下划线开头) 在一致性的实现中不被允许。 ( 6.8.10p2:"其他预定义的宏名应以前导下划线开头,后面紧跟大写字母或者第二个下划线,"但是,附录中提到 J.5 ( 可移植性问题), 这样的名字通常是预定义的)。

当我最初写这个答案,我无法找到任何文档在gcc这个问题,但我终于发现它,不是在 C implementation-defined行为c扩展cpp 手册部分 3.7.3, 它指出:

我们正在慢慢淡出所有在保留的命名空间之外的预定义宏。 你不应该在新程序中使用它们。。

因为 linux 是在编译器运行时定义的内置宏,或者为( 如果是 cross-compiler ) 编译,Linux 。

有很多这样的预定义宏。 使用 GCC,你可以使用:


cp/dev/null emptyfile.c
gcc -E -dM emptyfile.c

获取宏列表。 ( 我还没有说服GCC直接接受 /dev/null,但是空文件似乎正常运行。) 随着 GCC 4.8.1在 Mac OS X 10.8.5上运行,我得到了输出:


#define __DBL_MIN_EXP__ (-1021)
#define __UINT_LEAST16_MAX__ 65535
#define __ATOMIC_ACQUIRE 2
#define __FLT_MIN__ 1.17549435082228750797e-38F
#define __UINT_LEAST8_TYPE__ unsigned char
#define __INTMAX_C(c) c ## L
#define __CHAR_BIT__ 8
#define __UINT8_MAX__ 255
#define __WINT_MAX__ 2147483647
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __SIZE_MAX__ 18446744073709551615UL
#define __WCHAR_MAX__ 2147483647
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
#define __DBL_DENORM_MIN__ ((double)4.94065645841246544177e-324L)
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
#define __GCC_ATOMIC_CHAR_LOCK_FREE 2
#define __FLT_EVAL_METHOD__ 0
#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2
#define __x86_64 1
#define __UINT_FAST64_MAX__ 18446744073709551615ULL
#define __SIG_ATOMIC_TYPE__ int
#define __DBL_MIN_10_EXP__ (-307)
#define __FINITE_MATH_ONLY__ 0
#define __GNUC_PATCHLEVEL__ 1
#define __UINT_FAST8_MAX__ 255
#define __DEC64_MAX_EXP__ 385
#define __INT8_C(c) c
#define __UINT_LEAST64_MAX__ 18446744073709551615ULL
#define __SHRT_MAX__ 32767
#define __LDBL_MAX__ 1.18973149535723176502e+4932L
#define __UINT_LEAST8_MAX__ 255
#define __GCC_ATOMIC_BOOL_LOCK_FREE 2
#define __APPLE_CC__ 1
#define __UINTMAX_TYPE__ long unsigned int
#define __DEC32_EPSILON__ 1E-6DF
#define __UINT32_MAX__ 4294967295U
#define __LDBL_MAX_EXP__ 16384
#define __WINT_MIN__ (-__WINT_MAX__ - 1)
#define __SCHAR_MAX__ 127
#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1)
#define __INT64_C(c) c ## LL
#define __DBL_DIG__ 15
#define __GCC_ATOMIC_POINTER_LOCK_FREE 2
#define __SIZEOF_INT__ 4
#define __SIZEOF_POINTER__ 8
#define __USER_LABEL_PREFIX__ _
#define __STDC_HOSTED__ 1
#define __LDBL_HAS_INFINITY__ 1
#define __FLT_EPSILON__ 1.19209289550781250000e-7F
#define __LDBL_MIN__ 3.36210314311209350626e-4932L
#define __DEC32_MAX__ 9.999999E96DF
#define __strong 
#define __INT32_MAX__ 2147483647
#define __SIZEOF_LONG__ 8
#define __APPLE__ 1
#define __UINT16_C(c) c
#define __DECIMAL_DIG__ 21
#define __LDBL_HAS_QUIET_NAN__ 1
#define __DYNAMIC__ 1
#define __GNUC__ 4
#define __MMX__ 1
#define __FLT_HAS_DENORM__ 1
#define __SIZEOF_LONG_DOUBLE__ 16
#define __BIGGEST_ALIGNMENT__ 16
#define __DBL_MAX__ ((double)1.79769313486231570815e+308L)
#define __INT_FAST32_MAX__ 2147483647
#define __DBL_HAS_INFINITY__ 1
#define __DEC32_MIN_EXP__ (-94)
#define __INT_FAST16_TYPE__ short int
#define __LDBL_HAS_DENORM__ 1
#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL
#define __INT_LEAST32_MAX__ 2147483647
#define __DEC32_MIN__ 1E-95DF
#define __weak 
#define __DBL_MAX_EXP__ 1024
#define __DEC128_EPSILON__ 1E-33DL
#define __SSE2_MATH__ 1
#define __ATOMIC_HLE_RELEASE 131072
#define __PTRDIFF_MAX__ 9223372036854775807L
#define __amd64 1
#define __tune_core2__ 1
#define __ATOMIC_HLE_ACQUIRE 65536
#define __LONG_LONG_MAX__ 9223372036854775807LL
#define __SIZEOF_SIZE_T__ 8
#define __SIZEOF_WINT_T__ 4
#define __GXX_ABI_VERSION 1002
#define __FLT_MIN_EXP__ (-125)
#define __INT_FAST64_TYPE__ long long int
#define __DBL_MIN__ ((double)2.22507385850720138309e-308L)
#define __LP64__ 1
#define __DEC128_MIN__ 1E-6143DL
#define __REGISTER_PREFIX__ 
#define __UINT16_MAX__ 65535
#define __DBL_HAS_DENORM__ 1
#define __UINT8_TYPE__ unsigned char
#define __NO_INLINE__ 1
#define __FLT_MANT_DIG__ 24
#define __VERSION__"4.8.1"
#define __UINT64_C(c) c ## ULL
#define __GCC_ATOMIC_INT_LOCK_FREE 2
#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__
#define __INT32_C(c) c
#define __DEC64_EPSILON__ 1E-15DD
#define __ORDER_PDP_ENDIAN__ 3412
#define __DEC128_MIN_EXP__ (-6142)
#define __INT_FAST32_TYPE__ int
#define __UINT_LEAST16_TYPE__ short unsigned int
#define __INT16_MAX__ 32767
#define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 1080
#define __SIZE_TYPE__ long unsigned int
#define __UINT64_MAX__ 18446744073709551615ULL
#define __INT8_TYPE__ signed char
#define __FLT_RADIX__ 2
#define __INT_LEAST16_TYPE__ short int
#define __LDBL_EPSILON__ 1.08420217248550443401e-19L
#define __UINTMAX_C(c) c ## UL
#define __SSE_MATH__ 1
#define __k8 1
#define __SIG_ATOMIC_MAX__ 2147483647
#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2
#define __SIZEOF_PTRDIFF_T__ 8
#define __x86_64__ 1
#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF
#define __INT_FAST16_MAX__ 32767
#define __UINT_FAST32_MAX__ 4294967295U
#define __UINT_LEAST64_TYPE__ long long unsigned int
#define __FLT_HAS_QUIET_NAN__ 1
#define __FLT_MAX_10_EXP__ 38
#define __LONG_MAX__ 9223372036854775807L
#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL
#define __FLT_HAS_INFINITY__ 1
#define __UINT_FAST16_TYPE__ short unsigned int
#define __DEC64_MAX__ 9.999999999999999E384DD
#define __CHAR16_TYPE__ short unsigned int
#define __PRAGMA_REDEFINE_EXTNAME 1
#define __INT_LEAST16_MAX__ 32767
#define __DEC64_MANT_DIG__ 16
#define __INT64_MAX__ 9223372036854775807LL
#define __UINT_LEAST32_MAX__ 4294967295U
#define __GCC_ATOMIC_LONG_LOCK_FREE 2
#define __INT_LEAST64_TYPE__ long long int
#define __INT16_TYPE__ short int
#define __INT_LEAST8_TYPE__ signed char
#define __DEC32_MAX_EXP__ 97
#define __INT_FAST8_MAX__ 127
#define __INTPTR_MAX__ 9223372036854775807L
#define __LITTLE_ENDIAN__ 1
#define __SSE2__ 1
#define __LDBL_MANT_DIG__ 64
#define __CONSTANT_CFSTRINGS__ 1
#define __DBL_HAS_QUIET_NAN__ 1
#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1)
#define __code_model_small__ 1
#define __k8__ 1
#define __INTPTR_TYPE__ long int
#define __UINT16_TYPE__ short unsigned int
#define __WCHAR_TYPE__ int
#define __SIZEOF_FLOAT__ 4
#define __pic__ 2
#define __UINTPTR_MAX__ 18446744073709551615UL
#define __DEC64_MIN_EXP__ (-382)
#define __INT_FAST64_MAX__ 9223372036854775807LL
#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1
#define __FLT_DIG__ 6
#define __UINT_FAST64_TYPE__ long long unsigned int
#define __INT_MAX__ 2147483647
#define __MACH__ 1
#define __amd64__ 1
#define __INT64_TYPE__ long long int
#define __FLT_MAX_EXP__ 128
#define __ORDER_BIG_ENDIAN__ 4321
#define __DBL_MANT_DIG__ 53
#define __INT_LEAST64_MAX__ 9223372036854775807LL
#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2
#define __DEC64_MIN__ 1E-383DD
#define __WINT_TYPE__ int
#define __UINT_LEAST32_TYPE__ unsigned int
#define __SIZEOF_SHORT__ 2
#define __SSE__ 1
#define __LDBL_MIN_EXP__ (-16381)
#define __INT_LEAST8_MAX__ 127
#define __SIZEOF_INT128__ 16
#define __LDBL_MAX_10_EXP__ 4932
#define __ATOMIC_RELAXED 0
#define __DBL_EPSILON__ ((double)2.22044604925031308085e-16L)
#define _LP64 1
#define __UINT8_C(c) c
#define __INT_LEAST32_TYPE__ int
#define __SIZEOF_WCHAR_T__ 4
#define __UINT64_TYPE__ long long unsigned int
#define __INT_FAST8_TYPE__ signed char
#define __DBL_DECIMAL_DIG__ 17
#define __FXSR__ 1
#define __DEC_EVAL_METHOD__ 2
#define __UINT32_C(c) c ## U
#define __INTMAX_MAX__ 9223372036854775807L
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#define __FLT_DENORM_MIN__ 1.40129846432481707092e-45F
#define __INT8_MAX__ 127
#define __PIC__ 2
#define __UINT_FAST32_TYPE__ unsigned int
#define __CHAR32_TYPE__ unsigned int
#define __FLT_MAX__ 3.40282346638528859812e+38F
#define __INT32_TYPE__ int
#define __SIZEOF_DOUBLE__ 8
#define __FLT_MIN_10_EXP__ (-37)
#define __INTMAX_TYPE__ long int
#define __DEC128_MAX_EXP__ 6145
#define __ATOMIC_CONSUME 1
#define __GNUC_MINOR__ 8
#define __UINTMAX_MAX__ 18446744073709551615UL
#define __DEC32_MANT_DIG__ 7
#define __DBL_MAX_10_EXP__ 308
#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L
#define __INT16_C(c) c
#define __STDC__ 1
#define __PTRDIFF_TYPE__ long int
#define __ATOMIC_SEQ_CST 5
#define __UINT32_TYPE__ unsigned int
#define __UINTPTR_TYPE__ long unsigned int
#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD
#define __DEC128_MANT_DIG__ 34
#define __LDBL_MIN_10_EXP__ (-4931)
#define __SIZEOF_LONG_LONG__ 8
#define __GCC_ATOMIC_LLONG_LOCK_FREE 2
#define __LDBL_DIG__ 18
#define __FLT_DECIMAL_DIG__ 9
#define __UINT_FAST16_MAX__ 65535
#define __GNUC_GNU_INLINE__ 1
#define __GCC_ATOMIC_SHORT_LOCK_FREE 2
#define __SSE3__ 1
#define __UINT_FAST8_TYPE__ unsigned char
#define __ATOMIC_ACQ_REL 4
#define __ATOMIC_RELEASE 3

这是一个空文件中的236宏。 当我将 #include <stdio.h> 添加到文件中时,定义的宏数量上升到 505. 这些包括各种platform-identifying宏。

info gcc ( 强调挖掘):

-ansi

在C 模式下,这等同于 -std=c90 。 在 C++ 模式中,它相当于 -std=c++98 。 这关闭某些特性不符合iso人私下偷偷收藏盒式( 编译C 代码时) gcc,或标准 C++ ( 编译 C++ 代码时), 如 asmtypeof 关键词,和预定义的宏如'unix'和'vax', 确定你所使用的类型系统。 它还支持不需要的和很少使用的ISO三字符特性。 对于C 编译器,它禁用了 C++ 风格 // 注释和 inline 关键字的识别。

示例中(它使用 vax代替 linux因为写的时候可能是更受欢迎;-)。

基本思想是,当使用 -ansi 选项调用时,GCC只尝试完全遵守ISO标准。

...