免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5249 | 回复: 9
打印 上一主题 下一主题

[打架了打架了]UNIX痛恨者手册 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-02 19:12 |只看该作者 |倒序浏览
http://akey.peacewarfound.com/contents/Tooold/unix_haters.shtml

首页 / 兔偶得 / UNIX痛恨者手册
UNIX痛恨者手册

转载自:Simson Garfinkel, Daniel Weise, Steven Strassmann
原文由pengchengzou张贴
一本很有趣的书, 是那些用惯UNIX的人对UNIX的各种指责,诋毁,谩骂和嘲笑. 是由爱而生的恨. 即使当成一本高级笑话书,也是很有价值的.

UNIX痛恨者手册

By Simson Garfinkel, Daniel Weise, Steven Strassmann

第一章 UNIX

世界上第一个电脑病毒

“伯克利的两项最著名的产品是UNIX和LSD (一种**),我想这不是巧合”

病毒依赖于微小的个体和强大的适应性得以生存。它们并不复杂:它们没有为呼吸,新陈代谢,肌体活动等功能提供什么,只有足够的DNA或RNA以供繁衍。比如,肺炎病毒比起它们入侵的细胞要小得多,但它们在每个肺炎流行季节都能够产生新的变种,造成无数人死亡。

一个好病毒的特点是:

* 个头小
病毒做的事情不多,所以不需要很大。有人认为病毒不是生物,只是一些有破坏性的酸和蛋白质。
* 可移植性
病毒经常变异,以便以不同的方式攻击不同的细胞。据说AIDS就是由猴子身上的病毒变异而成的。
* 耗尽寄主的资源
* 快速变异

UNIX具有以上所有优点。在它刚诞生时,很小,功能不多,缺乏真正操作系统所需要的功能(如文件映射,告诉IO,健壮的文件系统,设备锁,合理的进程间通讯),它的移植性很好。UNIX耗尽主机的资源,没有系统管理员的时时呵护,UNIX会不断恐慌(panic),core dump,挂起。UNIX不断变异:同一个补丁在一个版本上工作,在另一个版本上就不行。

UNIX是有用户界面的计算机病毒。

标准化那些不一致的


--------------------------------------------------------------------------------

“标准的伟大之处在于它可以有很多” --- Grace Murray Hopper

自从UNIX 80年代开始流行以来,UNIX厂商一直在努力进行UNIX标准化工作。SUN, IBM,HP和DEC在这个他们自己制造的难题上倾注了数百万美元。

为什么UNIX厂商不喜欢UNIX标准化?

许多用户受够了复杂繁多的UNIX,最终只好使用Windows,因为他们的这个UNIX无法支持那个UNIX上的应用程序。

如果UNIX标准化了,谁还会买SUN的机器呢

标题: 第二章 欢迎新用户

欢迎新用户如同用一把上了六颗子弹的左轮枪玩俄罗斯轮盘赌Ken Thompson 自己设计过一辆汽车。和其他车不同,它没有速度计、汽油计,也没有那些愚蠢的指示灯讨司机的厌。如果司机犯了什么错误,仪表盘上就会出现一个大大的“?”。“有经验的司机,”Thompson说,“应该知道哪儿搞错了。”

计算机系统的新手需要一个友好的系统。至少,一个得体的系统会这样招待自己的客人:

与功能有逻辑关系的命令名
对危险命令的小心处理
一致的命令行为和命令行参数解析
易得和易读的在线文档
当命令失败时,给出可理解和有用的错误反馈

在建造UNIX的过程中,从没邀请过住户。来访的都是些戴着安全帽的建筑工人,被安插在这个破木板房子的各个角落。不幸的是,不仅没有人性因素(human factors)工程师的参与,而且住户的需要就从来没有被考虑过。所以抽水马桶、中央供暖、窗户等这些方便设施在后期就很难再添加了。但是建筑师们仍然为UNIX的设计而骄傲,似乎他们并不介意在一个没有烟火探测器的屋子里睡觉。 在其发展的大部分历史中,UNIX只是大学和工业研究人员的研究工具。随着大批便宜工作站的出现,UNIX作为平台软件进入了新时代。这一变化大约发生在1990年,其标志就是工作站厂商把C编译器从UNIX发布中剔除出去,以降低成本满足非开发用户的需求。可见,只是最近几年中UNIX厂商才开始考虑非程序员用户的需要,开始为他们提供shell以外的图形界面。

含糊的命令名

UNIX新手总是对UNIX对命令的命名表示惊讶。在DOS和Mac上受的教育不足以让他们体会到cp、rm、ls这类两字母命令的简洁和优美。

像我们这样用过70年代早期的IO设备的人都能理解,ASR-33 Teletype这类设备的速度、可靠性,以及它的键盘是万恶之源。和今天这种基于反馈原理、只需要关闭一个微开关的键盘不同,你必须用足力气揿下Teletype的键至少半英寸,以发动一个类似自行车上用的小型发电机,在上面操作要冒指骨骨折的危险。

如果当时Dennis和Ken用的是Selectric而不是Teletype,可能今天我们敲的将不是”cp”和”rm”而是”copy”和”remove”了。(Ken Thompson曾被问道如果他能重新设计UNIX他将做什么修改,他回答说:“我会在creat命令后加上个e。”),科技在拓宽我们的选择的同时,也能限制我们的选择,此一例也。

20多年过去了,还有什么理由延续这一传统呢?理由就是“历史的无可替代的力量”,历史就是那些存在的代码和教科书。如果一个厂商用remove替代了rm,那么所有UNIX教科书就不适用于这一系统了,每个使用rm的shell脚本都需要被修改。而且这也不合POSIX标准。

一个世纪前,打字高手由于击键过快,经常把打字键柄搅在一起,工程师设计了QWERTY键盘,于是问题得到了解决,因为没人能在这样的键盘上打得快。计算机的键盘不再有机械键柄,但QWERTY的键盘布局仍然在使用。同理,在未来的一个世纪中,我们仍然会继续使用rm。

事故会发生

用户十分关心自己的数据和文件。他们使用计算机来产生、分析和存储重要信息。他们相信计算机能够保护他们的重要财产。如果没有了这种信任,他们和计算机的关系就会蒙上阴影。UNIX辜负了我们的信任,它拒绝对使用危险命令的用户提供保护。比如rm就是以删除文件为目的的危险命令。

所有UNIX新手都有不小心无可挽回地删除重要文件的经历,即使是专家和系统管理员也遇到过。因此而每年损失的时间、精力可能价值几百万美元。这是个值得解决的问题;我们不理解为何UNIX一直拒绝解决这一问题。难道结果还不够悲惨么?

UNIX比其他操作系统更需要提供恢复删除功能,原因是:

UNIX文件系统没有版本功能

自动的版本维护能保留文件的历史版本,防止新版本冲掉老版本。
UNIX程序员在错误处理方面臭名昭著许多程序不检查是否所有内容都被写入了磁盘,或被写入的文件是否存在。有些程序总是删除输入文件。

UNIX shell扩展“*”,而不是其子命令

于是rm这样的命令就无法检查“*”这些危险的参数。即使是DOS也对”del *.*”有些提示。但在UNIX下,rm * 和 rm file1 file2…是没有区别的。

删除是永久的

UNIX没有undelete命令。许多其他更安全的系统则只是标记被删除文件所用的块为“可被使用”,然后把它移到一个特殊目录下。如果磁盘满了,这些文件块才会被重新使用。这一技术不是什么火箭科学,Macintosh在1984年就提出了“回收站”的想法,而Tenex早在1974年就采用了这一技术。连DOS也提供了简单的undelete功能,虽然并不总有效。

这四个问题互相合作,制造了无数无法恢复的重要文件。解决的方法早就存在,但UNIX“标准”版中却从来没有提供。

欢迎来到未来世界。

“rm”就是终结

许多实际的恐怖故事说明了以上的这些原则。以下是alt.folklore.computers新闻组上流传的一系列故事中的一个:

Date: Wed, 10 Jan 90
X-Virus: 6
From: djones@megatest.uucp (Dave Jones)
Subject: rm *
Newsgroups: alt.folklore.computers

是否有人曾想执行以下命令:

% rm *.o

结果却打成了:

% rm *>o

现在你得到了一个空文件o,以及大量的空间来存放它!

事实上,你可能连o也得不到,因为shell的文档并没有说o是在*被扩展前还是被扩展后被建立的。

上回书说到如何用rm获得一个空文件和很大的磁盘空间,下面是另一种用法:

Date: Wed, 10 Jan 90
X-Virus: 6
From: ram@attcan.uucp
Subject: Re: rm *
Newsgroups: alt.folklore.computers

我也被rm搞过。有一次我想删除一些/usr/foo/下的东西,我在/usr/foo下敲了以下命令:

% rm –r ./etc
% rm –r ./adm

当我要删除./bin目录时,我忘敲了那个点。我的系统似乎不太喜欢这个。

当受了这一致命一击后,UNIX就彻底完蛋了。聪明的系统会给用户一个恢复的机会(或至少提醒用户这一操作会导致系统崩溃)。

UNIX迷认为偶尔的文件误删除是正常的。比如,可以参考以下下面这个comp.unix.questions上的FAQ:

6) 如何反删除一个文件?

也许有一天,你不小心执行了一下这个命令:

% rm * .foo

然后发现你把“*”删掉了。你应该把这当作人生的一课。

当然称职的系统管理员应该定时备份系统。所以你最好问问他们手中是不是有你的文件备份。

“人生的一课”?没有任何一个其他厂商用这样的态度对待一个有缺陷的产品。“大人,我知道您的油箱炸了,但这是人生的一课。”“陪审团的先生女士们,我们将证明电锯保险开关的失效不过是给用户上的人生的一课。”不错。

改变rm的行为也不是个办法

被rm咬了几次后,往往会想到用”rm -i”替换rm,或整个替换掉rm,把所有被删除的文件放到~/.deleted目录中。这些小技巧让用户有了错误的安全感。

Date: Mon,16 Apr 90 18:46:33 199
X-Virus: 6
From: Phil Agre <agre@gargoyle.uchicago.edu>
To: UNIX-HATERS
Subject: deletion

在我们的系统上,“rm”并不真正删除文件,而是给文件换了名,这样”undelete”(不是unrm)这样的工具就能恢复被删的文件。

这个功能让我不再对删除文件多加小心,反正删掉了也能找回来。可是,我错了。Emacs中的删除并不支持这个功能,Dired命令也是如此。这当然是因为文件恢复并不是操作系统的一个功能。

所以,现在我脑子里有两个概念,一个是”deleting”一个文件,一个是”rm’ing”一个文件。当我的手要我的脑子删除一个文件时,我总要把这两个概念区分一遍。 一些UNIX专家由此得出了荒谬的结论,他们认为最好别把rm搞得更友好。他们争辩说,让UNIX更友好的努力往往适得其反。不幸的是,他们是对的。

Date: Thu, 11 Jan 90 17:17 CST
X-Virus: 6
From: merlyn@iwarp.intel.com (Randal L. Schwartz)
Subject: Don’t Overload commands! (was Re: rm *)
Newsgroups: alt.folklore.computers

请千万别让人用“安全”命令去替换标准命令。

(1) 许多shell程序会对多嘴的rm感到惊讶,而且也不会想到删除了的文件仍然占有磁盘空间。

(2) 并不是所有删除操作都是安全的,有户会因此产生一切都能恢复的错觉。

(3) 那些不标准的命令对系统管理员来说尤其可恨。如果你想有个有确认功能的”rm”,用下面的命令:

% alias del rm -i

千万别替换rm!

最近,comp.unix.questions上有过一次对系统管理员的调查,让他们说出最恐怖的系统管理故事。72小时内,就有了300多条回应。许多和我们上面描述的文件删除有关。可笑的是,这些可是UNIX高手。然而正是他们在对“UNIX对用户不友好”这类指责进行着辩护。

对用户不友好?UNIX对系统管理员又友好过么?请看

Date: Wed, 14 Sep 88 01:39 EDT
X-Virus: 6
From: Matthew P Wiener <weemba@garnet.berkeley.edu>
To: RISKS-LIST@kl.sri.com
Subject: “Single Keystroke”

在UNIX上,即使是有经验的用户也会误用rm。我从来没有误删除过文件,可是有一天,我用!r重复执行一个历史命令,我惊讶地发现被运行的是”rm –r *”。

为什么不能有个没有history功能的shell?

我还听到过一个用户试图删除一个名叫”*”的文件,好在他没有权限。

这个用户还想修改shell来避免对*进行展开。不幸的是,这个补救如同是在渗水的墙上再刷一层漆,治标不治本。

在线帮助

用户读打印文档的次数比他们参加选举投票的次数还要少。只有触手可及的在线文档才是有用的。下面我们看看UNIX的man是如何让最需要它的新用户失望的。

不是每个命令都是平等的,有些是外部命令,有些是内部命令。有些有man page,有些没有。UNIX要求你能区分这些命令。比如,wc, cp和ls是外部命令,它们都有man page,而fg, jobs, set和alias(这些长文件名是从哪里来的?)是内部命令,它们没有man page。

UNIX告诉新手用”man command”命令获得帮助,他们可不知道并不是所有命令都是如此。另外,如果他们的shell设置得有些不标准,他们就只能请教高手来获得帮助了。

错误信息和错误检查?没门!

新手很容易犯错误,比如用错命令,或用错选项。系统应该能识别这些错误,并且反馈给用户。不幸的是,UNIX程序从来不麻烦自己。相反,UNIX往往把各种错误混在一起,直到产生致命的结果。

上面一节我们说明了rm如何容易造成误删除。但你可能不知道不用rm也能很容易地误删除文件。

想删除你的文件么?试试编译器

一些cc版本经常根本不考虑用户的可能输入错误,而删除一些源代码文件。一些本科生常常着了道。

Date: Thu, 26 Nov 1992 16:01:55 GMT
X-Virus: 6
From: tk@dcs.ed.ac.uk (Tommy Kelly)
Subject: HELP!
Newsgroups: cs.questions
Organization: Lab for the Foundations of Computer Science, Edinburgh UK

我刚才想这么编译程序:

% cc –o doit doit.c

不小心敲成了:

% cc –o doit.c doit

不用说我的doit.c被冲掉了。有没有办法能恢复我的程序?(我干了整整一个上午)

其他一些程序也有同样的行为:

Date: Thu, 1 July 1993 09:10:50 - 0700
X-Virus: 6
From: Daniel Weise <Daniel@dolores.stanford.edu>
To: UNIX-HATERS
Subject: tarred and feathered

经过几次努力,我总算从欧洲的一个脆弱ftp站点上下载了了一个3.2M的文件。该untar它了。我敲了一下命令:

% tar –cf thesis.tar

…没有回应。

老天!

是不是该用x选项而不是c?

是的。

tar是不是给出了错误信息说没有指定输入文件?

没有。

tar是否感觉到有什么不对劲?

没有。

tar是不是真的什么也没有tar?

是的。

tar是否把thesis.tar用垃圾覆盖了?

当然,这就是UNIX。

我是不是需要再花 30分钟从欧洲下载这个文件?

当然,这就是UNIX。

我敢肯定有不少人遇到过这一不幸,有那么多的解决办法,比如:错误信息,文件版本化,确认用户是否想覆盖一个已有文件,等等等等。tar似乎在有意给用户找麻烦。 对于经常用tar备份的系统管理员来说,这个bug更是危险。不少系统管理员都曾经在备份脚本中错误地使用过“tar xf…”。在需要恢复备份的时候,才发现原来什么也没做。

欲知是否还有其他这样的恐怖命令,请听下回分解。

论坛徽章:
0
2 [报告]
发表于 2011-12-02 19:18 |只看该作者
算了,被敏感词打败,中间不贴了……

问:"C"和"C++"的名字是怎么来的?
答:这是他们的成绩

——Jerry Leichter

再没有比C++更能体现Unix“绝不给用户好脸”的哲学思想的了。

面向对象编程可以追溯到60年代的Simula语言,在70年代的Smalltalk语言上得到极大发展。许多书会告诉你面向对象语言如何能提高编程效率,使代码更健壮,和减少维护费用。不过你甭想在C++里得到这些。

这是因为C++根本就没理解面向对象的实质。非但没有简化什么,反而增加了更多的复杂性。和Unix一样,C++从没被好好设计过,它从一个错误走向另一个错误,是件打满补丁的破衣服。连自己的语法都没有严格定义(没一个语言敢这样),所以你甚至无法知道一行代码是不是合法。

把C++比做COBOL,其实是对COBOL的污辱。COBOL在那个时代的技术条件下,是做出了很不同凡响的贡献的。如果有谁用C++做成过什么事,那就算是很不同凡响了。幸运的是,很多不错的程序员知道必须尽量避免C++的伤害,他们只用C,对那些荒唐费解的功能敬而远之。通常,这意味着他们必须自己写个非面向对象的工具,以获得自己想要的功能。当然,他们的代码会显得极为怪异,失去兼容性,难于理解和重用。不过只要有一点儿C++的味道,就足够说服头头批准他们的项目。

许多公司已经被多年遗留下来的混乱难懂的COBOL代码搞得焦头烂额了。那些转而使用C++的公司刚刚意识到自己上了当。当然,这已经太晚了。软件灾难的种子已经播下了,浇水施肥,得到悉心照料,就等着十几年后长成参天大树了。等着瞧吧!


--------------------------------------------------------------------------------

面向对象的汇编语言


--------------------------------------------------------------------------------

C++没有一丝一毫高层次语言的特性。为什么这么说?让我们看看高层次语言应该具备那些特性: 优雅:在表示方式及其所表达的概念之间有着简单易懂的关系
抽象:高层次语言的每个表达式只表示一个概念。概念能够被独立表达并能自由使用
强大:高层次语言的能够对任何精确完整的程序行为进行提供直接了当的表述方式
高层次语言使程序员能够采用问题空间的方式描述解决方案。高层次的程序很容易维护,因为它们的目的性(intent)十分明确。根据一行高层次程序代码,现代编译器能够为各种平台生成高效的代码,所以高层次程序的可移植性和可重用性自然会很强。

使用低层次语言则需要对考虑无数细节,其中大部分是和机器内部操作有关的东西,而不是要解决的问题本身。这不但造成代码难于理解,而且很容易过时。现在几乎每隔今年就要更新系统,过时的必须花费很高代价修改低层代码或者彻底重写。 对不起,你的内存泄漏了

高层次语言对于常见问题有内置解决方案。例如,众所周知内存管理是产生错误最多的地方。在使用一个对象之前,你必须为它分配内存,适当进行初始化,小心跟踪使用,并正确释放。当然,每件事儿都异常乏味而且很容易出错,极小的一个错误可能会导致灾难性后果。定位和修改这类错误是臭名昭著的困难,因为它们对于配置或使用方式的变化极其敏感。

使用未分配内存的结构指针会造成程序崩溃。使用未正确初始化的结构也会使你的程序崩溃,不过不一定立刻完蛋。如果未能好好跟踪结构的使用情况,则很可能释放一块还在使用中的内存。还是崩溃。最好再分配一些结构用来跟踪那些结构对象。不过如果你太保守,不去释放那些不很肯定未在使用的内存,那么你可要小心了。内存中很快就会充斥着无用的对象,直到内存耗尽,程序崩溃。这就是恐怖的“内存泄漏”。 如果你的内存空间碎片太多,那该怎么办呢?解决办法是通过移动对象对内存重新归整,不过在C++里没戏——如果你忘了更新对象的所有引用(reference),那么你就会搞乱程序,结果还是崩溃。 很多真正的高层次语言提供了解决办法——那就是垃圾回收(garbage collector)。它记录跟踪所有的对象,如果对象用完了会加以回收,永远不会出错。如果你使用有垃圾回收功能的语言,会得到不少好处:

大量的bug立马无影无踪。是不是很爽呀?

代码会变得更短小更易读,因为它不必为内存管理的细节操心。

代码更有可能在不同平台和不同配置下高效运行。

唉,C++用户必须自己动手去拣垃圾。他们中的许多人被洗了脑子,认为这样会比那些专家提供的垃圾回收工具更为高效,如果要建立磁盘文件,他们估计不会使用文件名,而更愿意和磁道扇区打交道。手动回收垃圾可能会对一两中配置显得更高效些,不过你当然不会这么去使用字处理软件。

你不必相信我们这里说的。可以去读一下B. Zorn的《保守垃圾回收的代价测量》(科罗拉多大学Boulder分校,技术报告CU-CS-573-92),文中对程序员用C手动优化的垃圾回收技术和标准垃圾回收器进行了性能比较,结果表明C程序员自己写的垃圾回收器性能要差一些。

OK,假设你是个幡然醒悟的C++程序员,想使用垃圾回收。你并不孤单,很多人认为这是个好主意,决定写一个。老天爷,猜猜怎么着?你会发现根本没法在C++中提供其他语言内置的那样好的垃圾回收。其中一个原因是,(惊讶!)C++里的对象在编译后和运行时就不再是对象了。它们只是一块十六进制的烂泥巴。没有动态类型信息——垃圾回收器(还有调试器)没法知道任何一块内存里的对象究竟是什么,类型是什么,以及是否有人此时正在使用它。

另一个原因是,即使你能写个垃圾回收器,如果你用了其他未使用垃圾回收功能的代码,你还是会被干掉。因为C++没有标准的垃圾回收器,而且很有可能永远也不会有。假设我写了一个使用了我的垃圾回收功能的数据库程序,你写了一个使用你自己的垃圾回收功能的窗口系统。但你关闭一个装有我的数据记录的窗口,你的窗口不会去通知我的数据记录,告诉它已经没有人引用它了。这个对象将不会被释放,直到内存耗尽——内存泄漏,老朋友又见面了。

学起来困难?这就对了

C++和汇编语言很相象——难学难用,要想学好用好就更难了。

日期: Mon, 8 Apr 91 11:29:56 PDT
发信人: Daniel Weise <daniel@mojave.stanford.edu>
收信人: UNIX-HATERS
主题: From their cradle to our grave (从他们的摇篮到我们的坟墓)

造成Unix程序如此脆弱的一个原因是C程序员从启蒙时期就是这么被教育的。例如,Stroustrup(C++之父)的《C++编程语言》第一个完整程序(就是那个300K大小的"hello world"程序之后的那个)是一个英制/公制转换程序。用户用结尾"i"表示英制输入,用结尾"c"表示公制输入。下面是这个程序的概要,是用真正的Unix/C风格写的:

#include <stream.h>

main() {
[变量声明]
cin >> x >> ch;
;; A design abortion.
;; 读入x,然后读入ch。

if (ch == 'i') [handle "i" case]
else if (ch == 'c') [handle "c" case]
else in = cm = 0;
;; 好样的,决不报告错误。
;; 随便做点儿什么就成了。

[进行转换]

往后翻13页(第31页),给了一个索引范围从n到m的数组(而不是从0到m)的实现例子。如果程序员使用了超出范围的索引,这个程序只是笑嬉嬉地返回数组的第一个元素。Unix的终极脑死亡。


--------------------------------------------------------------------------------

语法的吐根糖浆(Syrup of Ipecac,一种毒药)


--------------------------------------------------------------------------------

语法糖蜜(Syntactic sugar)是分号癌症的罪魁祸首。

——Alan Perlis

在使用C编程语言中所能遇到的所有语法错误几乎都能被C++接受,成功编译。不幸的是,这些语法错误并不总能生成正确的代码,这是因为人不是完美的,他们总是敲错键盘。C一般总能在编译是发现这些错误。C++则不然,它让你顺利通过编译,不过如果真的运行起来,就等着头痛吧。

C++的语法形成也和它自身的发展密不可分。C++从来没有被好好设计过:它只是逐步进化。在进化过程中,一些结构的加入造成了语言的二义性。特别的规则被用于解决这些二义性,这些难懂的规则使得C++复杂难学。于是不少程序员把它们抄在卡片上以供不时之需,或者根本就不去使用这些功能。

例如,C++有个规则说如果一个字符串既可以被解析为声明也可以被解析为语句,那么它将被当做声明。解析器专家看到这个规则往往会浑身发冷,他们知道很难能正确实现它。AT&T自己甚至都搞不对。比如,当Jim Roskind想理解一个结构的意思时(他觉得正常人会对它有不同的理解),他写了段测试代码,把它交给AT&T的"cfront"编译器。Cfront崩溃了。

事实上,如果你从ics.uci.edu上下载Jim Roskind的开放C++语法,你会发现ftp/pub目录里的c++grammar2.0.tar.Z有这样的说明:“注意我的语法和cfront不一定保持一致,因为 a) 我的语法内部是一致的(这源于它的规范性以及yacc的确证。b) yacc生成的解析器不会吐核(core dump)。(这条可能会招来不少臭鸡蛋,不过...每次当我想知道某种结构的语法含义是,如果ARM(Annotated C++ Reference Manual, 带注释的C++参考手册)对它的表述不清楚,我就会拿cfront来编译它,cfront这时总是吐核(core dump))”

日期: Sun, 21 May 89 18:02:14 PDT
发信人: tiemann (Michael Tiemann)
收信人: sdm@cs.brown.edu
抄送: UNIX-HATERS
主题: C++ Comments (C++注释)

日期: 21 May 89 23:59:37 GMT
发信人: sdm@cs.brown.edu (Scott Meyers)
新闻组: comp.lang.c++
组织: 布朗大学计算机系

看看下面这行C++代码:

//**********************

C++编译器该如何处理它呢?GNU g++编译器认为这是一行由一堆星星(*)组成的注释,然而AT&T编译器认为这是一个斜杠加上一个注释开始符(/*)。我想知道哪个是正确解析方式,可是Stroustrup的书(《C++编程语言》)里面却找不到答案。

实际上如果使用-E选项进行编译,就会发现是预处理器(preprocessor)搞的鬼,我的问题是:

这是否AT&T预处理器的bug?如果不是,为什么?如果是bug,2.0版是否会得到修正?还是只能这么下去了?

这是否GNU预处理器的bug?如果是,为什么?

Scott Meyers

sdm@cs.brown.edu

UNIX解析中有个古老的规则,尽量接受最长的语法单元(token)。这样'foo'就不会被看成三个变量名('f', 'o'和'o'),而只被当成一个变量'foo'。看看这个规则在下面这个程序中是多么的有用(还有选择'/*'作为注释开始符是多么的明智):

double qdiv (p, q)
double *p, *q;
{
return *p/*q;
}

为什么这个规则没有被应用到C++中呢?很简单,这是个bug。

Michael

糟糕的还在后头,C++最大的问题是它的代码难读难理解,即使对于每天都用它的人也是如此。把另一个程序员的C++的代码拿来看看,不晕才怪。C++没有一丝品位,是个乱七八糟的丑八怪。C++自称为面向对象语言,却不愿意承担任何面向对象的责任。C++认为如果有谁的程序复杂到需要垃圾回收,动态加载或其他功能,那么说明他有足够的能力自己写一个,并且有足够的时间进行调试。

C++操作符重载(operator overloading)的强大功能在于,你可以把一段明显直白的代码变成能和最糟糕的APL, ADA或FORTH代码相媲美的东西。每个C++程序员都能创建自己的方言(dialect),把别的C++程序员彻底搞晕。

不过——嘿——在C++里甚至标准的方言也是私有的(private)。


--------------------------------------------------------------------------------

抽象些什么?


--------------------------------------------------------------------------------

你可能会觉得C++语法是它最糟糕的部分,不过当你开始学习C++时,就会知道你错了。一旦你开始用C++编写一个正式的大型软件,你会发现C++的抽象机制从根儿上就烂了。每本计算机科学教材都会这样告诉你,抽象是良好设计之源。

系统各个部分的关联会产生复杂性。如果你有一个100,000行的程序,其中每一行都和其他行代码的细节相关,那你就必须照应着10,000,000,000种不同的关联。抽象能够通过建立清晰的接口来减少这种关联。一段实现某种功能的代码被隐藏在模块化墙壁之后发挥作用。

类(class)是C++的核心,然而类的实现却反而阻碍着程序的模块化。类暴露了如此多的内部实现,以至于类的用户强烈倚赖着类的具体实现。许多情况下,对类做一点儿改变,就不得不重新编译所有使用它的代码,这常常造成开发的停滞。你的软件将不再“柔软”和“可塑”了,而成了一大块混凝土。

你将不得不把一半代码放到头文件里面,以对类进行声明。当然,类声明所提供的public/private的区分是没有什么用的,因为“私有”(private)信息就放在了头文件里,所以成了公开(public)信息。一旦放到头文件里,你就不大愿意去修改它,因为这会导致烦人的重编译。程序员于是通过修补实现机制,以避免修改头文件。当然还有其他一些保护机制,不过它们就象是减速障碍一样,可以被心急的家伙任意绕过。只要把所有对象都转换(cast)成void*,再也没有了讨厌的类型检查,这下世界清净了。

其他许多语言都各自提供了设计良好的抽象机制。C++丢掉了其中一些最为重要的部分,对于那些提供的部分也叫人迷惑不解。你是否遇到过真正喜欢模板(template)的人?模板使得类的实现根据上下文不同而不同。许多重要的概念无法通过这种简单的方式加以表达;即使表达出来了,也没法给它一个直接的名字供以后调用。

例如,名空间(namespace)能够避免你一部分代码的名字和其他部分发生冲突。一个服装制造软件可能有个对象叫做"Button"(钮扣),它可能会和一个用户界面库进行链接,那里面也有个类叫做"Button"(按钮)。如果使用了名空间,就不会有问题了,因为用法和每个概念的意思都很明确,没有歧义。

C++里则并非如此。你无法保证不会去使用那些已经在其他地方被定义了的名字,这往往会导致灾难性后果。你唯一的希望是给名称都加上前缀,比如ZjxButton,并但愿其他人不会用同一个名字。

日期: Fri, 18 Mar 94 10:52:58 PST
发信人: Scott L. Burson <gyro@zeta-soft.com>
主题: preprocessor (预处理器)

C语言迷们会告诉你C的一个最好的功能是预处理器。可事实上,它可能一个最蹩脚的功能。许多C程序由一堆蜘蛛网似的#ifdef组成 (如果各个Unix之间能够互相兼容,就几乎不会弄成这样)。不过这仅仅是开始。

C预处理器的最大问题是它把Unix锁在了文本文件的监牢里,然后扔掉了牢 旁砍 。这样除了文本文件以外,C源代码不可能以任何其他方式存储。为什么?因为未被预处理的C代码不可能被解析。例如:

#ifdef BSD
int foo() {
#else
void foo() {
#endif
/* ... */
}

这里函数foo有两种不同的开头,根据宏'BSD'是否被定义而不同。直接对它进行解析几乎是不可能的 (就我们所知,从来没实现过)。

这为什么如此可恶?因为这阻碍了我们为编程环境加入更多智能。许多Unix程序员从没见过这样的环境,不知道自己被剥夺了什么。可是如果能够对代码进行自动分析,那么就能提供很多非常有用的功能。

让我们再看一个例子。在C语言当道的时代,预处理器被认为是唯一能提供开码(open-coded,是指直接把代码嵌入到指令流中,而不是通过函数调用)的方式。对于每个简单常用的表达式,开码是一个很高效的技术。比如,取小函数min可以使用宏实现:

#define min(x,y) ((x) < (y) ? (x) : (y))

假设你想写个工具打印一个程序中所有调用了min的函数。听上去不是很难,是不是?但是你如果不解析这个程序就无法知道函数的边界,你如果不做经过预处理器就无法进行解析,可是,一旦经过了预处理,所有的min就不复存在了!所以,你的只能去用grep了。

使用预处理器实现开码还有其他问题。例如,在上面的min宏里你一定注意到了那些多余的括号。事实上,这些括号是必不可少的,否则当min在另一个表达式中被展开时,结果可能不是你想要的。(老实说,这些括号不都是必需的——至于那些括号是可以省略的,这留做给读者的练习吧)。

min宏最险恶的问题是,虽然它用起来象是个函数调用,它并不真是函数。看这个例子:

a = min(b++, c);

预处理器做了替换之后,变成了:

a = ((b++) < (c) ? (b++) : (c))

如果'b'小于'c','b'会被增加两次而不是一次,返回的将是'b'的原始值加一。

如果min真是函数,那么'b'将只会被增加一次,返回值将是'b'的原始值。


--------------------------------------------------------------------------------

C++对于C来说,就如同是肺癌对于肺


--------------------------------------------------------------------------------

“如果说C语言给了你足够的绳子吊死自己,那么C++给的绳子除了够你上吊之外,还够绑上你所有的邻居,并提供一艘帆船所需的绳索。”

——匿名

悲哀的是,学习C++成了每个计算机科学家和严肃程序最为有利可图的投资。它迅速成为简历中必不可少的一行。在过去的今年中,我们见过不少C++程序员,他们能够用C++写出不错的代码,不过...

...他们憎恶它。

论坛徽章:
0
3 [报告]
发表于 2011-12-02 20:29 |只看该作者
这架很难打起来啊,

论坛徽章:
7
荣誉版主
日期:2011-11-23 16:44:17子鼠
日期:2014-07-24 15:38:07狮子座
日期:2014-07-24 11:00:54巨蟹座
日期:2014-07-21 19:03:10双子座
日期:2014-05-22 12:00:09卯兔
日期:2014-05-08 19:43:17卯兔
日期:2014-08-22 13:39:09
4 [报告]
发表于 2011-12-02 20:43 |只看该作者
我们见过不少C++程序员,他们能够用C++写出不错的代码,不过...

...他们憎恶它。

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
5 [报告]
发表于 2011-12-02 20:55 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
6 [报告]
发表于 2011-12-03 23:13 |只看该作者
首页 / 兔偶得 / UNIX痛恨者手册
UNIX痛恨者手册

转载自:Simson Garfinkel, Daniel Weise, Steven ...
狗蛋 发表于 2011-12-02 19:12



    我想 rm *.o, 结果:
rm * .o
然后 。。。。。。。

论坛徽章:
0
7 [报告]
发表于 2011-12-06 09:16 |只看该作者
我大学的时候读过这本书

论坛徽章:
0
8 [报告]
发表于 2011-12-06 11:01 |只看该作者
C++发展得相对算的上比较符合作者意愿了。。。这里有几大段过时了。其它地方就没这么多。

论坛徽章:
0
9 [报告]
发表于 2011-12-06 13:33 |只看该作者
本帖最后由 sonicling 于 2011-12-06 13:36 编辑

如果有一天,计算机能懂自然语言的时候,这个世界就清净了,因为程序员都下岗了,反对者的祖先都被终结者暗杀了。

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
10 [报告]
发表于 2011-12-06 13:41 |只看该作者
如果有一天,计算机能懂自然语言的时候,这个世界就清净了,因为程序员都下岗了,反对者的祖先都被终结者暗 ...
sonicling 发表于 2011-12-06 13:33


我顶
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP