前言
大家也看到题目了,这篇文章是《C语言程序设计》里面的第一章内容,苏小红,高等教育出版社。因为看到第一章后,觉得写得很好,就码下来分享给大家。在看之前,可以先大概浏览一下,内容不算少。不过,很具有“故事”的色彩,很生动。值得一看。
游戏、黑客和C语言
1969年的美国贝尔实验室是当时科技界的梦工厂,集结了这世界上最富有创造力的科学家和工程师,其中包括数位诺贝尔奖获得者。他们一起创造了无数影响着全人类的发明,比如数码相机的核心——电荷耦合原件就是那一年在贝尔实验室诞生的。
这些人的成就貌似高不可攀,但其实也都是凡人,在某些方面和我们也是非常相似的。比如当他们见到一台强大的计算机时,心里最先想到的也可能是用它来玩游戏。那个时代,计算机是大型机构才能拥有的奢侈品,在这上面玩游戏实在是暴殄天物。但谁在乎呢,追求快乐是最重要的,所以他们为了痛快地玩游戏而没少动脑筋。
那时候是没有商业游戏的, 想有游戏玩,首先要发挥DIY(Do It Yourself)精神,自己编写。自己编的游戏被别人喜欢,是当时最有面子的事情。有一个叫Ken Thompson(以下尊称为ken)的工程师,26岁,看到阿波罗11号载人飞船登月成功,觉得挺酷,就设计了一个叫“Space Travel”的游戏。在游戏中,玩家驾驶着宇宙飞船,在虚拟的太阳系里穿梭,欣赏美景的同时,还可以在各个行星、卫星表面降落。这个游戏先是在Mutlics系统上编写,后来又在GENCOS系统上重写。能运行这两个系统的机器都是笨重的大型机,虽然运算能力出众,但显示效果很差,而且机时费非常高,玩一次需要支付75美元(当时美国人均月收入大约200美元)。这实在是太贵了。于是他同其同事Dennis M.Ritchie(以下尊称dmr)一起寻找免费的“游戏机”。功夫不负有心人,还真被他们找到了一台。
这就是PDP-7小型机,由DEC制造,拥有当时最先进的图形处理能力。那时计算机的主要用途是数据处理,图形能力并不太重要,所以PDP-7更多的时候是静静的躺着,很少被使用,直到ken和dmr发现了它。
可以玩游戏了。然而,游戏的运行需要操作系统的支持。PDP-7当时还是“裸机”,没有能在其上运行的操作系统。于是,他俩挽起袖子开始为PDP-7编写操作系统,并给这个系统起了一个名字——UNIX。直到今天,UNIX仍然是最受信任的操作系统,它既支撑着军队、政府、电力、电信和银行等大型机构的关键业务,也是苹果Mac系列计算机的动力之源,甚至iPhone、iPod Touch的魅力也部分拜其所赐。
UNIX起初是用汇编语言编写的,那是一种更接近机器而不是人的语言。计算机能直接读懂的语言叫机器语言,它所有的语句都是由“0”和“1”两个数字构成的,根本就不是给人看的。当最后一个机器语言程序员“疯掉”以后,人们终于开始琢磨怎么让计算机读懂自然语言。基本思路是做一个翻译程序,直接把自然语言翻译成机器语言。这种翻译程序被命名为“编译器”。但是直接理解自然语言太难了,直到现在还没能完全实现,所以就折中一下,设计一种尽量接近自然语言,且还能被精确翻译为机器语言的语言,这种语言就是人们常说的编程语言。学编程的过程,其实就是学习怎样用编程语言说话让编译器听懂的过程。第一种编程语言肯定是最接近机器而远离人类的,他就是汇编语言。虽然看上去有几分像自然语言,比如加法叫“ADD”,减法叫“SUB”,但它的语法完全是机器的,每一行语句都和一条机器指令严格对应。不同计算机的机器指令是不一样的,所以针对一种计算机编写的汇编程序不能在另一种计算机上直接使用,必须重写(Space Travel就被重写过很多次)。用专业术语来说,汇编语言缺少“可移植性”。
UNIX的优雅加上Space Travel的吸引力,使很多人希望他们的计算机上也能安装UNIX。于是ken和dmr决定改用高级语言编写UNIX,这样它就可以在更多类型的计算机上运行。
除了机器语言和汇编语言以外,几乎所有编程语言都被统称为高级语言。它的特点是更接近自然语言,而与机器语言基本没有瓜葛。不同的高级语言编译器可以把同样的高级语言程序翻译成适应不同机器的指令,因而高级语言大多具有较好的可移植性。
故事讲到这里,该本书的主角——C语言隆重登场了。决定使用高级语言后,在语言的选择上,ken和dmr遇到了麻烦。当时可供选择的高级语言有很多,包括直到现在还在被使用的BASIC和FORTRAN等。这些语言都是面向应用程序编写而设计的,层次有些太高,距离机器太远,都假想自己是在一个操作系统上运行,所以不适合用来开发操作系统。DIY精神再次发挥作用,他俩决定自己设计一种适合编写UNIX的高级语言。那一年是1972年,ken继续完善UNIX,dmr设计新语言,两人一起开发编译器。因为该语言以ken早年设计的B语言为基础,所以就自然而然地被命名为C语言。
1983年,因为UNIX和C语言的巨大成功,ken和dmr共同获得了计算机界的最高奖——图灵奖。玩游戏到这等境界,恐怕古今很难再找到第三人。
UNIX和C,得其一便富可敌国。然而,他俩从一开始就没有想去申请专利、商标、软件著作权等法律保护,而是把所有的一切,包括最宝贵的源代码,都全部公开发布了。对他们来说,自己写的程序有人使用,就是最大的快乐,也是最大的财富。这恰好使得很多机构和个人都具有了自如地为UNIX和C添加代码、做各种贡献的条件,因而又极大地促进了它们的发展。
从上面的故事,我们可以发现ken和dmr的很多可爱之处:
- 做事情以兴趣为出发点,并不在乎未来会怎样;
- 极富钻研精神,喜欢迎接挑战;
- 乐于分享,不计回报。
这些特点正是正宗“黑客精神”的集中体现。这里笔者觉得很有必要澄清一下什么是“正宗”的黑客,以免给两位前辈抹黑。
后来出现一些急功近利或别有用心的人,他们利用黑客找到的漏洞去破坏别人的系统,盗窃别人的数据,以期达到不可告人的目的。这种人居然也自称“黑客”,而且曝光率非常高,于是在大众眼中,“黑客”一词已成为擅长进入他人系统进行破坏的人的专有名词。这种结果让人痛心,但也无奈。希望读者能理解,本书中谈到的“黑客”都是指颇有侠义精神的正宗黑客。
Ken Thompson和Dinnis M. Ritchie被奉为黑客圈子里的英雄,大家都尊称他们为ken和dmr(必须小写)。几十年过去了,黑客圈子里再没有第二个人敢叫“ken”,虽然这是一个在英语圈里司空见惯的名字。
C和UNIX、脚本语言至今仍是年轻黑客被圈子接受前必须苦练的三大技艺。由黑客设计,被黑客推崇,所以C语言自身也处处闪耀着黑客精神的光芒,这种光芒使它能够永葆青春。
C语言,不老的传说
最受欢迎的歌一定是被听的最多的,那么最受欢迎的语言一定是被用的最多的。C语言现在用的多吗?在业界,一般答案是:如果一件事情可以用X语言做,就一定不要用C语言做。这里的X可以代指任何语言。天啊,这好像是在说“如果可以听X的歌,就一定不要听周杰伦的歌”。
哪种编程语言最受欢迎呢?每个人都有自己的看法。还是用客观数据说话吧。下面是Tiobe在2017年4月公布的程序设计语言受欢迎程度的排名和走势。目前C语言占据第二位,也算是曾经的王者。
能不用就不用,还如此受欢迎,这就有些让人费解了。dmr曾经说过一句话:“C诡异离奇,缺陷重重,并获得巨大成功。”因为诡异且有缺陷,所以会被尽量避免使用,取而代之的是弥补了这些缺陷的语言。因为确实获得了巨大成功,所以它至今仍大受欢迎。到底有多成功,最受欢迎的10中语言中,有7种都直接使用、间接引用或部分借鉴了C语言的语法(比如,它们语句的结尾都要有一个“;”),只有VB和Python的语法里找不到C的影子。凭这等世界第一的影响力,受到欢迎也就在情理之中了。但为什么却被尽量避免使用呢?那是因为它让人爱恨交织。
C语言的爱与恨
C语言设计原则的第一条是:“信任程序员”。对程序设计语言了解不多的人,不会觉得这句话怎样。但对真正的程序员来说,凭这句话就足以对C语言爱上一辈子。
在C语言流行的年代,计算机相当昂贵,但速度比不上现今的手机,内存都以千字节为单位计算。所以,那时候对程序的最基本的要求就是效率。C语言完全满足人们对效率的苛求,精心设计的代码可以极大地节约资源,又不像汇编语言那样难用,所以受到程序员的欢迎。后来,硬件越来越便宜,性能越来越高,程序的运行效率已经不再是追求的主要目标,安全性、稳定性和易于维护等变得重要起来,C语言的弊端变显现了。
C语言给程序员最大的发挥空间,让他们可以自由地在代码中挥洒激情和创意,从不去质疑这些代码是否合理,因为它“信任程序员”,相信程序员的决定一定是正确的,即便有错误,也一定能自己修正。无限制的自由,在某些人的手中是创造力的源泉,而在另外一些人手中,却能称为混乱的根源。随着软件系统规模的膨胀,需要的程序员越来越多,软件出现错误的概率就越来越大。每一个低级的错误都可能会引发大的灾难。很多人把这种乱象产生的原因归罪于C语言给程序员的自由,开始怀疑它,甚至痛恨它,却从不反省自己糟糕的编码能力。于是有人说,给这匹野马加上缰绳吧,别让它再恣意狂奔。但是C语言拒绝锁链,于是很多语言穿上C语言的外衣,自己挂上锁链,站了出来。它们看上去很像C语言,所以大家很容易接受。它们挂着锁链,所以它们不再信任程序员,而是指手画脚的告诉程序员,这件事情该怎么做,那件事情不能怎么做。如果程序员不听它们的,它们就拒绝工作。这样乱象解除了,开发速度也加快了,多人合作容易了,错误减少了,对程序员能力的需求降低了,因而工资也降低了,老板开心了,业界繁荣了。平心而论,“一件事情可以用X语言做,就一定不用C语言做”确实是一个很好的策略,尽管程序员会失去一些自由,但在合法的范围内仍有一定的空间可以发挥创造力,而且这些创造力很少创造出负面效果,能让老板、程序员、用户皆大欢喜。但程序员,尤其是受人尊敬的程序员,他们的血液中天生就充满着不安分,向往自由的黑客生活,所以他们会一边抚摸着身上的伤疤,一边怀念那个鲁莽却无往不利的老将军,怀念在他手下无拘无束的日子,怀念被他激发出的无尽潜能。这个老将军是程序员心中永远的战神。
C语言教给我们的故事
现在,还需要使用C语言的地方大概只限于下面四个领域:
- C语言仍然是编写操作系统的不二之选。它为操作系统而生,能更直接地与计算机底层打交道,精巧、灵活、高效。最重要的是,操作系统的开发者都是顶尖的程序员,他们有充足的能力和经验驾驭C语言。
- 在对程序的运行效率有苛求的地方,比如嵌入式领域,C语言也是首选,因为C语言是目前执行效率最高的高级语言。不过,嵌入式系统现在的硬件性能也已经足够强大,而功能要求越来越高,所以C语言的生存空间正在缩小。
- 在需要继承或维护已有C代码的地方,还需要C语言。有很多影响深远的软件和程序库最早都是用C语言开发的,所以还要继续应用C语言。但是,它们中的很多已经开始使用其他语言重写,那些C语言的代码早晚有一天会被抛弃。
- 因为学过C语言的人最多,熟悉C语言风格语法的人更多,所以C语言成为思想交流的首选媒介语言。比如,书籍里如果必须要出现程序,最常见的是C程序;在涉及编程能力考查的笔试、面试时,C语言通常都是必考的。
应用面如此之窄,学它能有多大用处呢?如果单纯从“用不上”这个角度得出“学C语言没有用”的结论,是有失公允的。即便对计算机及其相关专业而言,C语言的“用处”也不算大。学习C语言的意义并不在于使用它,而在于它可以让我们了解很多基本的道理。
这里不妨根据未来的职业要求,把读者分为三类:
(1)不需要编程;
(2)需要编程,但不使用C语言;
(3)需要编程,且要使用C语言。
对第三类读者,没什么好说的,不仅要好好学,而且要精深地学。别看学过C语言的人很多,但真正会用它的,相当少。
对第二类读者而言,学习C语言最大的好处是可以更直接地体会计算机最基本的工作模式和方式。换言之,就是能了解一些计算机底层的原理。这是在其他高级语言中很难体会到的。这些原理虽然也不常直接用到,但它们潜移默化的影响是惊人的,总是能在关键时刻发挥作用。另一个好处是C语言很适合作为入门级语言。这并不是C语言自身决定的,而是中国庞大的C语言教育体系决定的。关于C语言的书籍、资料、论坛、习题和教辅系统等是最多的,而且无一例外都是面向程序设计的初学者。相比之下,其他语言的很多教材是假定读者已经有一定的编程经验,不介绍或只简单介绍那些通用的基本概念、理论与思维,直接跳到语言自身的特性。当然,像Java、C++等语言也有很好的面向初学者的教材,直接学习它们可以了解更新更好的编程思想,距离实际应用更近,成效更显著。好在大多数主流编程语言都是与C语言一脉相承的,使得从C语言入门后,再学其他语言,并不会感到困难。
C语言给第一类读者的最大好处对第二、第三类读者同样有效,那就是C语言会为我们打开一扇了解计算机的窗口。在几乎做任何事情都离不开计算机的今天,越了解计算机也就意味着越能利用好计算机。
美国卡内基梅隆大学计算机科学系前主任周以真教授在2006年发表了一篇著名的文章——《计算思维》。文中谈到“计算机科学的教授应当为大学新生开一门称为‘怎么像计算机科学家一样思维’的课,面向非专业的,而不仅仅是计算机科学专业的学生”,这是因为“机器学习已经改变了统计学。······计算机生物学正在改变着生物学家的思考方式。类似地,计算机博弈理论正改变着经济学家的思考方式,纳米计算改变着化学家的思考方式,量子计算改变着物理学家的思考方式”,所以“计算思维代表着一种普遍的认识和一类普适的技能,每一个人,不仅仅是计算机科学家,都应热心于它的学习和运用”。不过遗憾的是,我们现在还很少有学校开设这样的课程。所以程序设计课在某种程度上肩负了传播计算思维的责任。这也是对于不需要编程的学生而言,最大的意义之所在。
什么是编程
已经确定要学习C语言,现在开始正式进入程序的世界。先了解一下什么是编程。
“编程”是“编写程序”的简称,术语称为“程序设计”。程序是计算机的主宰,控制着计算机该去做什么事。所有托付给计算机去做的事情都要被编成程序。假如没有程序,那么计算机什么事情都干不了。例如,没有安装QQ的计算机就不能上QQ。如果程序是“好”程序,那么计算机在它的指挥下可以又快又好地完成工作;如果程序有错误,那么计算机也会严格按照错误的指令去工作,能造成什么后果,就要看错到什么程度了。所以编程这件工作非常重要。
如果我们想让计算机做一件事情,但是没有现成的程序可用,就需要编程。编程的第一步是“需求分析”,就是要弄清楚我们到底要让计算机做什么。这个过程貌似很简单,也确实不少人对它不屑一顾。但忽视它的结果就像考试时审题审的不对,后面的解题再漂亮,也拿不到分数,必须从头返工。所以有经验的程序员都会对需求分析相当谨慎。需求分析中最难的事情是开发者和用户之间的交流。用户不懂开发,开发者不懂用户的专业和业务,使双方都会有对牛弹琴的感觉,导致需求分析的过程要持续好几个月,甚至数年。如果开发者之前对专业就有所了解,或者用户懂一点点开发,这件事就好办得多了。这也是非计算机专业的学生学习程序设计的一点儿好处。
编程的第二步是“设计”,就是搞明白计算机该怎么做这件事情。设计的内容主要包括两方面,一方面是设计算法、数学建模,用数学方法对问题进行求解;另一方面是设计程序的代码结构,使程序更易于修正、扩充、维护等。数学部分往往属于非计算机专业范畴,程序设计部分则属于计算机专业范畴。两者的配合非常重要。并不是所有的数学模型都能用程序高效实现,而有些数学中难以处理的问题,却可以利用计算机的特点巧妙解决。计算思维就体现在这里。
编程的第三步才是真正的编写程序,即把设计的结果编程一行行代码,输入到程序编辑器中。虽然Windows内置的记事本也可用来编写程序,但一个顺手的编辑器可让编码的过程充满惬意。有经验的程序员喜欢使用VIM或Emacs,如果有钻研精神,可以试试。新手一般会选择更容易入门的集成开发环境(IDE),如:Code::Blocks,Microsoft Visual Studio等。
编程的第四步是调试程序,就是将源代码编译,变成可执行的程序,然后运行之,看看是否能满足第一步的要求。如果不满足,就要查找问题,修改代码,再重新编译、运行,直到满意为止。用到的主要工具是编译器和调试器,它们一般都已经内置在IDE中。如果不使用IDE,只是使用编辑器,则需要单独安装。推荐使用gcc编译器和gdb调试器。两者占据UNIX/Linux平台的主流,在Windows平台上亦可使用。
这个过程说起来简单,但每一个环节都有很多学问在里面。编写小程序的话,第三步编写程序和第四步调试程序比较重要。程序规模比较大时,前两步的重要性超过后两步。
小结
C语言,黑客精神的产物,令人痴迷。但只有少数的人会成为黑客,所以对大多数人来说,学习C语言最重要的是领会程序设计的要旨,领会计算思维。但这些不是几句话、几页纸、几次课就能讲的透的,需要在不断的程序设计实践中用心体会。多多编程,编的多了,自然就精熟了。