C語言發展史的點點滴滴。
任何一種新事物的出現都不是來自於偶然,而是時代所驅使的必然結果。
如果你問我:C語言有多偉大。那麼,我可能會想一下,說:多偉大我不知道,但是我知道很偉大。
這裡,我想說一句可能有點片面的話,就是:如今這世界上,凡是帶電的地方,可能都會有她(C語言)或者她的子孫的影子。
一、C語言發展史
1. 語言之父
丹尼斯·麥卡利斯泰爾·裡奇(英語:Dennis MacAlistair Ritchie,1941年9月9日-2011年10月12日),美國計算機科學家。黑客圈子通常稱他為「dmr」。他是C語言的創造者、Unix作業系統的關鍵開發者,對計算機領域產生了深遠影響,並與肯·湯普遜同為1983年圖靈獎得主。
丹尼斯.裡奇 生平時間線
麻省理工大學計算機系的馬丁教授評價說:"如果說,賈伯斯是可視化產品中的國王,那麼裡奇就是不可見王國中的君主。賈伯斯的貢獻在於,他如此了解用戶的需求和渴求,以至於創造出了讓當代人樂不思蜀的科技產品。然而,卻是裡奇先生為這些產品提供了最核心的部件,人們看不到這些部件,卻每天都在使用著。"
2. C語言的先輩
2.1BCPL語言之父
馬丁·理察德(英語:Martin Richards,1940年7月21日-),生於英國,計算機科學家,為BCPL程式語言的發明者,發展了TRIPOS作業系統。
1966年,馬丁·理察德在劍橋大學,以CPL程式語言為基礎,發明了BCPL程式語言。
2.2B語言之父
肯尼斯·藍·湯普遜(英語:Kenneth Lane Thompson,1943年2月4日-)小名肯·湯普遜(英語:Ken Thompson),美國計算機科學學者和工程師。黑客文化圈子通常稱他為「ken」。在貝爾實驗室工作期間,湯普遜設計和實現了Unix作業系統。他創造了B語言(基於BCPL) — C語言的前身,而且他是Plan 9作業系統的創造者和開發者之一。與丹尼斯·裡奇同為1983年圖靈獎得主。
2006年,湯普遜進入Google公司工作,與他人共同設計了Go語言。
一組Ken與Dennis的照片
左Ken,右Dennis
1999年獲得美國國家技術獎 [左一:Ken | 左二:Dennis | 右一:柯林頓]
從這些老照片中,我隱隱約約看到了幾行小字,寫著:
1.與優秀之人為伍
2.互相成就
試想,有多麼重要?
3. C語言時間線
從圖中時間線,可以明顯的看出C語言的起源以及時間節點。
有時候不得不說時勢造英雄,在1969~1971年之間著名的作業系統Unix從肯.湯普遜手中誕生,作為一種大型的系統性軟體來說,極其需要一種可靠的高級語言的出現(當時的低級語言指的是彙編,因為之前的作業系統是用彙編寫的)。
這個時候的丹尼斯.裡奇也沒閒著,在對B語言改良之後,就誕生了帶有類型的C語言(據裡奇自己說,有一段時間稱這種改良的語言為NB。即:new B。不過,在我們這些吃瓜群眾眼中看來也確實NB)。
4. unix時間線
Unix的誕生與C語言被廣泛的傳播、使用,有著密切的聯繫。
上圖時間線只顯示前幾個與C語言在相同時間段內誕生的Unix版本(當然,感興趣的話,可以查詢Unix相關發展史,絕對會讓你大吃一驚。其中最著名的幾個分支:BSD、minix、Linux...)。
下面,通過在網上找得到的部分Unix內核源碼,來追溯一下C語言出現的時機。
4.1 PDP-Unix
PDP-Unix系統內核代碼文件
可以看到基本都是用彙編寫的(文件名後綴.s)。為什麼用基本這個詞呢?因為,在系統裡面有一部分命令是用B語言寫的。
4.2 First Edition Unix
First Edition Unix系統內核代碼文件
可以看到,還是用彙編寫的(文件名後綴.s)。
4.3 Second Edition Unix
Second Edition Unix系統內核代碼文件
到這個版本,已經可以看到C語言的身影了。
4.4 Unix與C語言
從C語言在Unix V2版本出現之後,Unix的V3版本開始,已經可以在Unix內核中見到大量C語言編寫的代碼。
據裡奇所說:到1973年初,現代C的基本知識已經完成。C語言和編譯器強大到,足以讓我們在當年夏天用C重寫PDP-11的Unix內核 (也就是Unix的V3版本)。
到了這個時間節點,基本可以肯定的是C語言、Unix的大部分核心都已經完善。剩下要做的就是,可移植性、標準化。
後面的故事,大家可能也聽說過:後來學術和政府組織中都在使用Unix,也正是由於Unix的風靡與興盛,帶動了C語言被廣泛的傳播、使用。
在1980年代,C語言的使用廣泛傳播,並且幾乎所有機器體系結構和作業系統都可以使用編譯器。尤其是,它已成為個人計算機的編程工具,無論是用於這些機器的商業軟體製造商,還是對編程感興趣的最終用戶,都非常受歡迎。
這也就是所謂的互相成就。
一句話概括就是:不畏得失、日漸精進,最終互相成就。
5. 第一個C語言編譯器是怎樣編寫的?
不知道你有沒有想過,大家都用C語言或基於C語言的語言來寫編譯器,那麼世界上第一個C語言編譯器又是怎麼編寫的呢?這不是一個「雞和蛋」的問題……
回顧一下C語言歷史:Tomphson在BCPL的基礎上開發了B語言,Ritchie又在B語言的基礎上成功開發出了現在的C語言。在C語言被用作系統程式語言之前,Tomphson也用過B語言編寫過作業系統。可見在C語言實現以前,B語言已經可以投入實用了。因此第一個C語言編譯器的原型完全可能是用B語言或者混合B語言與PDP彙編語言編寫的。
我們現在都知道,B語言的執行效率比較低,但是如果全部用彙編語言來編寫,不僅開發周期長、維護難度大,更可怕的是失去了高級程序設計語言必需的移植性。
所以早期的C語言編譯器就採取了一個取巧的辦法:先用彙編語言編寫一個C語言的一個子集的編譯器,再通過這個子集去遞推,進而完成完整的C語言編譯器。
詳細的過程如下:先創造一個只有C語言最基本功能的子集,記作C0語言,C0語言已經足夠簡單了,可以直接用彙編語言編寫出C0的編譯器。依靠C0已有的功能,設計比C0複雜,但仍然不完整的C語言的又一個子集C1語言,其中C0屬於C1,C1屬於C,用C0開發出C1語言的編譯器。
在C1的基礎上設計C語言的又一個子集C2語言,C2語言比C1複雜,但是仍然不是完整的C語言,開發出C2語言的編譯器 …… 如此直到CN,CN已經足夠強大了,這時候就足夠開發出完整的C語言編譯器的實現了。
至於這裡的N是多少,這取決於你的目標語言(這裡是C語言)的複雜程度和程式設計師的編程能力。簡單地說,如果到了某個子集階段,可以很方便地利用現有功能實現C語言時,那麼你就找到N了。下面的圖說明了這個抽象過程:
而這個過程也在Unix V2版本中找到了證據。
肯恩·湯普森,丹尼斯·裡奇和其他人在貝爾實驗室為PDP-11開發了Unix的第二版。它通過更多的系統調用和更多的命令擴展了第一版。此版本還看到了C語言的開始,該語言用於編寫一些命令。
此處的代碼僅是某些命令,某些庫函數和C編譯器的原始碼。c /中的文件來自 last1120c.tar.gz 磁帶,並構成了第二版Unix的有效C編譯器。
二、BCPL、B、C語言
如果想要找到一種好的方式,來進行程式語言之間的比較的話,那麼非代碼莫屬。
1. 3種語言代碼示例
下面分別使用BCPL、B、C三種語言實現一個簡單的程序:程序將三個數字a、b、c相加,並將結果賦值給sum,最後列印總和。
1.1 BCPL語言示例
LET 聲明變量
:= 符號為賦值符號 Go中也有該符號,表示函數內部局部變量。這裡感覺很有意思的一點是:最初B語言之父肯.湯普遜把:=符號改成了=符號。現在,也作為Go語言之父之一,又把:=符號請回來了(冥冥之中的命運~)。
1.2 B語言示例
B語言的語言結構
B語言代碼示例
語句auto ...是一個聲明。即,它定義了要在函數內使用的局部變量。putnumb 是一個帶參數的庫函數,它將在終端上列印一個數字。
1.3 C語言示例
2. 示例代碼中三者的區別
2.1 通過上面例子可以看出三者的區別:
C語言寫法更接近於B語言
BCPL、B語言都是無類型的語言,用word/cell表示一個固定長度的bit,C語言是有類型的
2.2 有一些地方,你可能感興趣:
++、-- 符號是Thompson發明的
&&、|| 是在C語言引入的
2.3 說明:
查了好久只找到了BCPL、B語言的部分代碼片段,至於能不能跑起來,我也不知道 ^_^
如果想要知曉三者的具體區別的話,建議閱讀丹尼斯.裡奇關於《C語言發展史》的文章
BCPL、B語言也有經歷過若干次版本迭代
C語言更接近與B語言,或著說是在B的基礎上不斷的添加了很多新特性。
三、歷史為什麼選擇C語言
1960s年代後期,貝爾實驗室對計算機系統的研究進入繁盛時期。MIT、General Electric、Bell實驗室合作的Mutlics項目以失敗而告終(1969年左右)。
就是在這個時期,Ken Tompson開始寫Mutlics的替代品,他希望按照自己的設計構造一個令人舒服的計算系統(也就是Unix)。後來在寫出第一個版本的Unix時,覺得Unix上需要一個新的系統程式語言,他創造了一個B語言。B語言是沒有類型的C,準確說B語言是Tompson把BCPL擠進8K內存,被其個人大腦過濾後的產生的語言。
由於B語言存在的一些問題,導致其只是被用來寫一些命令工具使用。恰好在這個時期,Ritchie在B語言的基礎上,進行了重新的設計改良,從而誕生了C語言。
1973年,C語言基本上已經完備,從語言和編譯器層面已經足夠讓Tompson和Ritchie使用C語言重寫Unix內核。後來,Unix在一些研究機構、大學、政府機關開始慢慢流行起來,進而帶動了C語言的發展。
1978年,K&R編寫的《The C Programming Language》出版,進一步推動了C語言的普及。
用一句話總結就是:對的時間、對的地點,出現了對的人以及工具 (Unix與C語言的關係,有點像GNU與Linux kernel的關係,都是互相成就)。
四、標準C庫及代碼
C語言及其標準經過若干次迭代之後,就成了今天大家看到的樣子。其標準中指定了很多C標準庫,而不同的系統都有自己不同的代碼實現。
當然,Linux內核中也有實現了標準C庫的代碼,下面一起欣賞她的美。
1. 標準C庫
ANSI C共包括15個頭文件。1995年,(NA1)批准了3個頭文件增加到C標準函數庫中。C99標準增加6個頭文件。C11標準中又新增了5個頭文件。
至此,C標準函數庫共有29個頭文件:
2. linux/lib/string.c
下面列出3個字符串處理函數 strcpy()、strncpy()、strncat()。代碼出自Linus Benedict Torvalds之手,為什麼這麼說?看代碼頭部注釋,還是那個熟悉的味道stupid。看過git原始碼的人應該也會知道,git源碼中也有類似注釋。
五、廉頗老矣,尚能飯否
經歷過幾十年的風雨洗禮,C語言可謂風光無數,這世界上隨處可見它的身影。但是,同時在一些人眼裡,可能覺得C語言已是暮年(將近50歲)、老矣。如同下圖:
如果你真這樣想,那你就錯了。
TIOBE 2020-09 程式語言排行榜告訴你,C語言寶刀未老,還是那個風採耀眼的少年。
個人想說的是,只要計算機還是基於馮諾依曼體系結構,晶片還是基於物理製程。那麼,都會有一片C的天空。因為,她知道一個最接近天空的地方(C是最接近彙編、機器語言的高級語言之一)。
*總結:
猛然間發現已經到了總結,但是還覺得仍舊意猶未盡,這並不是我心目中最真實的那個她。但是,我還是希望你看完本文之後,能夠多少了解與熟悉C的美與真實。