当前位置: 首页 > 知识库问答 >
问题:

为什么C预处理器将“Linux”这个词解释为常数“1”?

笪成周
2023-03-14

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

测试C:

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

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

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

这当然会产生一个错误。

(顺便提一下:stdio.h文件中没有#define linux。)

共有1个答案

蒋芷阳
2023-03-14

在旧时代(ANSI之前),预定义UNIXVAX等符号是允许代码在编译时检测其编译对象是什么系统的一种方法。当时没有官方语言标准(除了K&R第一版后面的参考资料之外),任何复杂的C代码通常都是一个复杂的迷宫,包括#ifdef,以允许系统之间的差异。这些宏定义通常由编译器本身设置,而不是在库头html" target="_blank">文件中定义。由于没有关于实现可以使用哪些标识符和为程序员保留哪些标识符的真正规则,编译器编写者可以随意使用诸如unix这样的简单名称,并假定程序员只是为了自己的目的而避免使用这些名称。

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

因此,任何预定义UNIXlinux的编译器都是不一致的,因为它将无法编译使用类似int linux=5;的完全合法的代码。

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

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

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

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

一个很不相关的例子:1987年国际模糊C代码竞赛的“最佳One Liner”获奖者David Korn(是的,Korn Shell的作者)利用了预定义的unix宏:

main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}

它打印“unix”,但其原因与宏名的拼写完全无关。

 类似资料:
  • 这当然会产生错误。 (顺便说一句:在文件中没有。)

  • 问题内容: 为什么 GCC* 中的 C 预处理器将单词(小写字母)解释为常量? * test.c: 的结果(在预处理阶段之后停止): 当然哪个会产生错误。 (顺便说一句:没有中的文件。) 问题答案: 在过去(ANSI之前的版本)中,预定义符号(例如和)是一种允许代码在编译时检测其针对哪个系统进行编译的方法。当时没有正式的语言标准(除了K&R第一版后面的参考资料之外),任何复杂的C代码通常都是s 的

  • 我有一个简单的批处理测试文件test.bat如下行: 当我运行它时,我希望得到的是测试,而不是: 为什么batch会试图解释这条评论?或者这里发生了什么?如果我去掉注释,脚本会按预期打印测试。 文件中也没有提到这一点。

  • 问了这个问题后,我很困惑,于是决定为一个C编译器程序构建类似的测试。这是我的代码: 使用选项在GCC下编译 测试代码被更改,这样错误值只能在运行时知道(而不能在编译时知道),这样GCC优化器就不能删除循环的代码。 我们应该期待CPU的加速吗?(正如GCC编译程序预测的那样)

  • 这个问题不仅仅是让这个词有意义,还提醒造词者告诉我们他们为什么给这个词起名字,这可不是一件小事,这会让我们更舒服地学习新知识,我们想学什么就学什么。 例如,许多人想知道为什么Swift使用这个词,或者为什么Objective-C使用文件扩展名? 我认为官方的文件或回应是非常重要的,任何猜测或假设都没有帮助,因为它没有说服力,迷惑的人还是迷惑的人。 我在官方论坛上也问过这个问题: https://d

  • 本文向大家介绍深入理解C预处理器,包括了深入理解C预处理器的使用技巧和注意事项,需要的朋友参考一下 C 预处理器不是编译器的组成部分,是编译过程中一个单独的步骤。C预处理器只是一个文本替换工具,它会指示编译器在实际编译之前完成所需的预处理。 所有的预处理器命令都是以井号(#)开头。它必须是第一个非空字符,为了增强可读性,预处理器指令应从第一列开始。 下表包含所有重要的预处理器指令: 指令 描述 #