为什么C预处理器解释“linux"这个词?作为常数“1"? [英] Why does the C preprocessor interpret the word "linux" as the constant "1"?

查看:20
本文介绍了为什么C预处理器解释“linux"这个词?作为常数“1"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Why does the C preprocessor in GCC interpret the word linux (small letters) as the constant 1?

test.c:

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

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

Result of $ gcc -E test.c (stop after the preprocessing stage):

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

这当然会产生错误.

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

(BTW: There is no #define linux in the stdio.h file.)

推荐答案

在旧时代(ANSI 之前),预定义符号如 unixvax 是一个允许代码在编译时检测它正在编译的系统的方法.当时没有官方语言标准(除了第一版 K&R 后面的参考资料),任何复杂的 C 代码通常都是 #ifdef 的复杂迷宫,以允许对于系统之间的差异.这些宏定义通常由编译器本身设置,而不是在库头文件中定义.由于对于实现可以使用哪些标识符以及哪些标识符是为程序员保留的没有真正的规则,编译器作者可以随意使用像 unix 这样的简单名称,并假设程序员会简单地避免将这些名称用于他们自己的目的.

In the Old Days (pre-ANSI), predefining symbols such as unix and vax was a way to allow code to detect at compile time what system it was being compiled for. There was no official language standard back then (beyond the reference material at the back of the first edition of K&R), and C code of any complexity was typically a complex maze of #ifdefs to allow for differences between systems. These macro definitions were generally set by the compiler itself, not defined in a library header file. Since there were no real rules about which identifiers could be used by the implementation and which were reserved for programmers, compiler writers felt free to use simple names like unix and assumed that programmers would simply avoid using those names for their own purposes.

1989 年 ANSI C 标准引入了限制实现可以合法预定义的符号的规则.编译器预定义的宏的名称只能以两个下划线开头,或者下划线后跟一个大写字母,让程序员可以随意使用与该模式不匹配且未在标准库中使用的标识符.

The 1989 ANSI C standard introduced rules restricting what symbols an implementation could legally predefine. A macro predefined by the compiler could only have a name starting with two underscores, or with an underscore followed by an uppercase letter, leaving programmers free to use identifiers not matching that pattern and not used in the standard library.

因此,任何预定义 unixlinux 的编译器都是不符合标准的,因为它将无法编译使用诸如 int 之类的完全合法的代码linux = 5;.

As a result, any compiler that predefines unix or linux is non-conforming, since it will fail to compile perfectly legal code that uses something like int linux = 5;.

碰巧的是,gcc 在默认情况下是不符合标准的 -- 但可以通过正确的命令行选项使其符合(相当好):

As it happens, gcc is non-conforming by default -- but it can be made to conform (reasonably well) with the right command-line options:

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

有关详细信息,请参阅gcc 手册.

See the gcc manual for more details.

gcc 将在未来版本中逐步淘汰这些定义,因此您不应编写依赖于它们的代码.如果您的程序需要知道它是否正在为 Linux 目标编译,它可以检查是否定义了 __linux__(假设您使用的是 gcc 或与其兼容的编译器).有关详细信息,请参阅GNU C 预处理器手册.

gcc will be phasing out these definitions in future releases, so you shouldn't write code that depends on them. If your program needs to know whether it's being compiled for a Linux target or not it can check whether __linux__ is defined (assuming you're using gcc or a compiler that's compatible with it). See the GNU C preprocessor manual for more information.

一个基本上不相关的旁白:1987 年 国际混淆 C 代码竞赛的Best One Liner"获胜者,David Korn(是的,Korn Shell 的作者)利用了预定义的 unix 宏:

A largely irrelevant aside: the "Best One Liner" winner of the 1987 International Obfuscated C Code Contest, by David Korn (yes, the author of the Korn Shell) took advantage of the predefined unix macro:

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

它打印 "unix",但原因与宏名称的拼写完全无关.

It prints "unix", but for reasons that have absolutely nothing to do with the spelling of the macro name.

这篇关于为什么C预处理器解释“linux"这个词?作为常数“1"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆