《C专家编程》一1.11 轻松一下——由编译器定义的Pragmas效果

简介:

本节书摘来自异步社区《C专家编程》一书中的第1章,第1.11节,作者 【美】Perter Van Der Linde,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.11 轻松一下——由编译器定义的Pragmas效果

自由软件基金会(Free Software Foundation)是一个独特的组织,它由MIT顶级黑客Richard Stallman所创立。顺便提一下,我们所说的“黑客”,它的原先意思是“天才程序员”。后来这个称呼被媒体所贬损,致使它在局外人眼中成了“邪恶的天才”的代名词。和形容词“bad”一样,“黑客”现在也有两个相反的意思,必须通过上下文才能明白它的确切意思。

Stallman成立自由软件基金会的初衷是:软件应该是免费的,所有人都可以自由使用。FSF的宗旨是“消除在计算机程序拷贝、重发布、理解和修改方面的限制”,它雄心勃勃地想建立一个UNIX的自由软件实现方案,称为GNU(它代表“GNU's Not UNIX”,对,确实如此)。

许多计算机科学研究生和其他人赞同GNU的哲学,他们设计软件产品,由FSF进行打包并免费发布。通过这些甘心奉献的有天赋的程序员们的辛勤劳动,产生了一些优秀的软件作品。FSF最好的作品之一就是GNU C编译器系列。gcc是一个健壮的、在代码优化方面具有创造性的编译器,可以在很多硬件平台使用,有时甚至比编译器厂商的产品更为优秀。gcc并不适合所有的项目,它在维护性和未来版本连续性方面仍存在一些问题。在现实的开发中,除了编译器之外,还需要很多工具。曾有很长一段时间,GNU的调试器无法在共享库中工作。而且在开发时,GNU C偶尔会让人感到眼花缭乱。

在制订ANSI C标准时,引入了pragma指示符,这个指示符来源于Ada。#pragma用于向编译器提示一些信息,诸如希望把某个特定函数扩展为内联函数,或者取消边界的检查。由于它并非C语言所固有,pragma遭到了一个gcc编译器设计者的积极抵制,他把这个“由编译器定义的”的效果做得很搞笑——在gcc 1.34版,如果使用了pragma,将会导致编译器停止编译,而是运行一个计算机游戏!在gcc手册中有如下说明:

在ANSI C标准中,“#pragma”指令会产生一个由编译器定义的任意效果。在GNU C预处理器中,一旦遇见“#pragma”指令,它首先试图运行“rogue”游戏;如果失败,尝试运行“hack”游戏;如果还是失败,它会尝试运行GNU Emacs,显示汉诺塔(Tower of Hanoi)。如果仍然失败,它就报告一个致命错误。总之,预处理过程不会继续下去。

—— GNU C编译器1.34版手册

GNU C编译器中关于预处理器的那部分源代码如下:

/ *
 * #pragma指示符的行为是由编译器定义的。
 * 在GNU C编译器中,它的定义如下:
 * /
do_pragma()
{
    close(0);
    if(open("/dev/tty", O_RDONLY, 0666) != 0)
                         goto nope;
    close(1);
    if(open("/dev/tty", O_WRONLY, 0666) != 1)
                         goto nope;
    exel("/usr/games/hack", "#pragma", 0);
    exel("/usr/games/rogue", "#pragma", 0);
    exel("/usr/new/emacs", "-f", "hanoi", "9", "-kill", 0);
    exel("/usr/local/emacs", "-f", "hanoi", "9", "-kill", 0);
nope:
  fatal("you are in a maze of twisty compiler features, all different");
}

特别好笑的是,用户手册中的描述是错误的,它把“hack”和“rogue”的次序搞反了。

[1] 学习、使用和实现PL/I的困难使一位程序员写了这样一首打油诗:“IBM有个PL/I,语法比JOSS还糟糕,到处都见它踪影,实实在在是垃圾。JOSS是个老古董,它可不是因简单而闻名。”

[2]  “BCPL:A Tool for Compiler Writing and System Programming(BCPL,编译器编写和系统编程的工具),” Martin Richards, Proc. AFIPS Spring Joint Computer Conference, 34(1969), pp.557-566。BCPL并非“Before C Programming Language(C前身编程语言)”的首字母缩写,尽管这是个有趣的巧合。它的确切意思是“Basic Combined Programming Language(基本组合编程语言)”。basic的意思是“不花哨”,它是由英国伦敦大学和剑桥大学的研究人员合作开发的。Multics实现了一种BCPL编译器。

[3] 本书原版出于1994年,当时距1970年还不到30年。——译者注

[4] ANSI C Rationale(单独)可通过匿名FTP,从ftp.uu.net下载,位于/doc/standards/ansi/X3.159-1989/(如果你不明白匿名FTP,赶紧到附近的书店买一本关于Internet的书,免得成为信息高速公路上的“跛行的羔羊”)。Rationale的纸版书也已出版,ANSI C Rationale, 新泽西Silicon Press,1990。ANSI C标准本身无法从任何ftp站点下载,因为标准印刷本的营业收入是ANSI的重要收入来源之一。

[5] 如果你想刨根问底,它位于第5.1.1.3段,“Diagnostics(诊断)”。作为一个语言标准,它不会简单地说“在一个不正确的程序里,你必须为每个错误准备一个标志”。作为标准,其用辞必然骈四骊六,仿佛是由靠玩弄文字吃饭的律师所撰写的。它的正式用辞如下:“一个遵循标准的实现应该*至少为每个翻译单元产生一条诊断信息,其中包含了所有违反语法规则或约束的行为。在其他情况下不必产生诊断信息”。
*Brian Scearce+ 所总结的有用规律——如果你听到一个程序员说“应该(shall)”,那么他一定在引用标准里的说法。
+嵌套脚注(nested footnote)的发明者。

[6] The New Hacker's Dictionary把语言律师定义为“能从200多页的手册中提取5句话,拼起来放到你面前,你只要一看就能明白自己问题的答案的人”,嘿!在这个例子的情况下正是如此。

[7] 即int是32位。——译者注

[8] 即long 是32位而int是16位。——译者注

[9] 即long和int均为32位。——译者注

[10] The Elements of Programming Style, Kernighan(对,就是那个Kernighan)和Plauger,纽约,McGraw Hill,1978。这是一本文字流畅、细节真实的优秀作品——非常值得购买,你能从中获益良多。

相关文章
|
7月前
|
Go
Go语言构造函数的力量:初始化和配置的艺术
Go语言构造函数的力量:初始化和配置的艺术
48 0
|
7月前
|
Go
这波操作太秀了!Go语言函数变量大解析
这波操作太秀了!Go语言函数变量大解析
67 0
|
1月前
|
存储 编译器 Linux
解析编程中不可或缺的基础:深入了解结构体类型
解析编程中不可或缺的基础:深入了解结构体类型
34 1
|
2月前
|
安全 编译器 程序员
【C++ 泛型编程 高级篇】C++ 编程深掘:静态成员函数检查的艺术与实践
【C++ 泛型编程 高级篇】C++ 编程深掘:静态成员函数检查的艺术与实践
71 0
|
2月前
|
存储 算法 安全
【C++ 泛型编程 高级篇】 C++编译时函数调用技术深度解析
【C++ 泛型编程 高级篇】 C++编译时函数调用技术深度解析
39 1
|
6月前
|
编译器 C语言
【C语言航路外传】如何隐藏代码及声明和定义的在工程中真正的使用场景
【C语言航路外传】如何隐藏代码及声明和定义的在工程中真正的使用场景
62 1
|
7月前
|
存储 C++
软件开发入门教程网之C++ 常量
软件开发入门教程网之C++ 常量
30 0
|
9月前
|
自然语言处理 数据库连接
编译原理(五) 语言的定义
编译原理(五) 语言的定义
100 0
|
11月前
|
存储 算法 编译器
抽丝剥茧C语言(高阶)结构体,枚举,联合+练习
抽丝剥茧C语言(高阶)结构体,枚举,联合+练习
|
12月前
|
存储 C++
软件开发入门教程网之C++ 常量
常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。 常量可以是任何的基本数据类型,可分为整型数字、浮点数字、字符、字符串和布尔值。 常量就像是常规的变量,只不过常量的值在定义后不能进行修改。