官术网_书友最值得收藏!

建議1:認識ANSI C

談到C語言的發展歷程,就不得不從最早的二進制語言說起。大家都知道,二進制語言可以說是世界上最早的計算機語言,它只允許程序設計人員使用計算機能夠直接識別和執行的二進制代碼(即0和1,其中,0代表低電壓,1代表高電壓)來編寫程序。可想而知,這樣的編碼方式對程序設計人員來說是多么困難與枯燥。因此,為了提高程序設計效率并減輕程序設計人員的負擔,所以后來很快便出現了匯編語言(Assembly Language)。

與二進制語言一樣,匯編語言也是面向機器的程序設計語言,不同類型的計算機上需要提供不同的匯編語言。但與二進制語言不同的是,匯編語言使用助記符(Memoni)來代替操作碼,并用地址符號(Symbol)或標號(Label)來代替地址碼。由于匯編語言采用符號代替二進制代碼,因此,它也被稱為符號語言。使用匯編語言編寫的程序機器并不能直接識別,而需要通過一種程序將匯編語言翻譯成機器能夠識別的二進制語言,這種起翻譯作用的程序就是匯編程序。

相對于二進制語言,匯編語言不僅使開發效率得到了很大提升,而且它還具有許多優點,比如它能夠直接同計算機的底層軟件或硬件進行交互,直接訪問與硬件相關的存儲器或I/O端口;能夠不受編譯器的限制,對生成的二進制代碼進行完全控制;能夠對關鍵的代碼進行更準確地控制,避免因線程共同訪問或硬件設備共享而引起的死鎖;能夠根據特定的應用對代碼進行最佳優化,提高運行速度等。

盡管如此,匯編語言依舊是一種層次非常低的語言,它僅僅高于直接手工編寫二進制的機器指令碼。在實際應用中,它仍然暴露了一些不可避免的缺陷:如編寫的代碼非常難以閱讀,不好維護;很容易產生bug,難于調試;一般只能針對特定的體系結構和處理器進行優化;開發效率很低,時間長且單調等。因此,我們更加需要一種設計描述簡單,能脫離對機型的要求,并且能在任何計算機上運行的計算機語言,我們稱這種語言為高級語言。這樣,程序設計人員就可以將問題及解決問題的算法過程描述出來,利用這種高級語言直接寫出各種表達式來描述簡單的計算過程,而無須針對不同的機型編寫不同的代碼。

注釋 高級語言編寫的程序稱為源程序,源程序不能在計算機上直接運行,必須將其翻譯成二進制代碼后才能執行。一般有兩種翻譯方式:一種是“解釋程序”方式,即將源程序作為輸入,翻譯一句后就提交計算機執行一句,這種方式并不形成目標程序;另一種是“編譯程序”方式,即將源程序作為輸入,全部翻譯成二進制代碼后再執行,編譯后的二進制程序稱為目標程序。

世界上出現的第一種高級語言是Algol語言,它也可以算作C語言的前身。它和普通語言表達式非常接近,適用于數值計算,所以Algol多用于科學計算機。1960年Algol 60版本推出后,很受程序設計人員歡迎。Algol 60推出了許多新的概念,如局部性概念、動態、遞歸、巴科斯-諾爾范式(Backus-Naur Form,BNF)等。從某種意義上講,Algol 60應該是程序設計語言發展史上的一個里程碑,它標志著程序設計語言已成為一門獨立的科學學科,并為后來的軟件自動化及軟件可靠性的發展奠定了基礎。

雖然使用Algol 60來描述算法很方便,但是它離計算機硬件系統卻很遠,不宜用來編寫系統程序。1963年英國劍橋大學在Algol語言的基礎上增添了處理硬件的能力,并命名為“CPL”(Combined Programming Language),即復合程序設計語言。但由于CPL的規模很大,學習和掌握都比較困難,因此沒有流行。1967年劍橋大學的Martin Richards對CPL語言進行了簡化,推出BCPL(Basic Combined Programming Language),即基本復合程序設計語言。它是典型的面向過程的高級語言,它的語法更加靠近機器本身,適合于開發精巧、高要求的應用程序,而且它對編譯器的要求也不高。同時,BCPL也是最早使用庫函數封裝基本輸入輸出的語言之一,這使得它的跨平臺可移植性很好。

1969年,美國通用電氣公司、麻省理工學院與貝爾實驗室聯合創建了一個龐大的項目,命名為Muktics工程。該項目的目的是創建一個操作系統,不過由于該項目過于復雜和龐大,最終失敗了。這也致使項目的參與者之一通用電氣公司退出軟件領域,同時,貝爾實驗室的專家們也撤出了Muktics工程,轉而研究新的領域。之后,貝爾實驗室的一位名為Ken Thompson研究員和他的同事Dennis Ritchie組成一個非正式的小組,開始進行一些其他方面的研究。為了自娛自樂,Ken Thompson把他的“太空旅行”軟件移植到不太常用的PDP-7系統上。與此同時,Ken Thompson還為PDP-7系統編寫了一個簡單的操作系統。該操作系統比起Muktics工程簡單了許多,采用匯編語言編寫,1970年Brian Kernighan為其取名為UNIX。

注意 從這里可以看出,著名的操作系統UNIX是早于C語言出現的,后來才用C語言重寫此系統,這一點一定要注意。

不過使用匯編語言編寫程序不僅吃力而且效率低下,所以Ken Thompson就考慮利用高級語言的特性來解決這一問題。1970年,Ken Thompson進一步簡化了BCPL,突出硬件的處理能力,并取“BCPL”的第一個字母“B”作為新語言的名稱,即B語言。同時,他還使用B語言編寫了UNIX操作系統程序。不過B語言還是存在許多問題,最大問題就在于無法表達不同的數據類型,而且效率不高,這也迫使Ken Thompson后來不得不在PDP-11的基礎上重新使用匯編語言來實現UNIX。面對B語言存在的問題,1971年Dennis Ritchie通過增加類型擴展了B語言,這次采用的是編譯模式而不是解釋模式,并且引入了類型系統,每個變量在使用前必須聲明。這種擴展的B語言稱為NB,即New B的縮寫。

1972年,Ken Thompson和Dennis Ritchie繼續對B語言進行完善和擴充,他們在保留B語言強大硬件處理能力的基礎上,擴充了數據類型,恢復了通用性,并取“BCPL”的第二個字母“C”作為新語言的名稱,即C語言。其實,C語言除了增加類型系統外,它還增加了許多方便編譯器設計者設計的新特性,主要表現在以下幾個方面:

數組下標從0開始,而不是從1開始。例如,我們定義一個數組arr[50],因為C語言的數組下標是從0開始的,所以它的合法范圍是arr[0]~arr[49]。因此,你不能夠向arr[50]里存儲數據。

□ 可以把數組看作指針,它簡化了參數的傳遞方法,使大家不必忍受傳遞一個數組到函數時需要復制所有數組內容的低效率。不過,值得注意的是,數組與指針并非在任何情況下都是等效的,這一點會在后面進行詳細闡述。

□ float類型被自動擴展為double類型。雖然在ANSI C中情況不再如此,但最初浮點數常量的精度都是double類型的,所有表達式中float類型的變量總會被自動轉化為double類型。

□ 增加register關鍵字,用此關鍵字告訴編譯器設計者哪些變量被放到了寄存器中,從而簡化編譯器,但卻也因此給程序員帶來了無窮無盡的麻煩,這一點會在后面的章節中詳細闡述。

此后,兩人又合作重寫了UNIX操作系統,C語言也伴隨著UNIX操作系統成為一種廣受歡迎的計算機語言。圖1-1按時間順序闡述C語言的由來。

圖1-1 C語言的由來

1978年,為了讓C語言脫離UNIX操作系統,成為任何計算機上都能運行的通用計算機語言,Brian Kernighan和Dennis Ritchie共同撰寫了《The C Programming Language》的第1版,該著作簡稱為“K&R”。書中對C語言的語法進行了規范化描述,書末的參考指南則給出了當時C語言的完整定義,這也成為當時C語言事實上的標準,此標準稱為“K&R C”。從此以后,C語言被移植到各種機型上,并受到廣泛支持。

隨著C語言在多個領域的推廣和應用,一些新的特性不斷被各種編譯器實現并添加進來。于是建立一個新的“無歧義、與具體平臺無關的C語言定義”就成為越來越重要的事情。1983年,美國國家標準委員會ANSI(American National Standards Institute)屬下專門負責信息技術標準化的機構ASC X3(現已更名為國際信息技術標準委員會(International Committee for Information Technology Standards,INCITS))成立了一個專門的技術委員會J11(J11是委員會編號,全稱是X3J11),用于起草關于C語言的標準草案。1989年,ANSI正式通過C語言標準草案,至此該標準成為美國國家標準,此標準也稱為C89標準。

隨后,《The C Programming Language》第2版出版發行,書中內容根據ANSI C(C89)進行了更新。1990年,在ISO/IEC JTC1/SC22/WG14(即ISO/IEC聯合技術第I委員會第22分委員會第14工作組)的努力下,ISO批準ANSI C成為國際標準,于是ISO C(又稱為C90)誕生。與C89相比,C90除了標準文檔的印刷編排細節有些不同外(主要表現在刪除了“Rationale”一節,并把文檔的格式與段落編碼作了改動),它們在技術上是完全一樣的。到目前為止,C89是C語言運用得最廣泛的標準,基本上所有的C語言編譯器都完全支持該標準。相對于“K&R C”,C89主要做了以下幾方面的改進:

□ 增加了新特性——原型。原型是函數聲明的擴展,它使得編譯器很容易根據函數的定義檢查函數的用法。

□ 增加了一些新的關鍵字,如enum、const、volatile、signed與void。C89的關鍵字見表1-1。

表1-1 C89關鍵字表

□ 除此之外,C89還做了許多其他的改進,如增強了預處理指令,定義了相關的宏,允許將結構本身作為參數傳遞給函數,從“無符號保留”轉到“值保留”等。

自ISO C(C90)推出之后,ISO又于1994年與1996年分別出版了C90的技術勘誤文檔,更正了一些印刷錯誤,同時,在1995年還通過了一份C90的技術補充,這份補充對C90進行了微小擴充,擴充后的ISO C被稱為C95。

1999年,ANSI和ISO又通過了最新版本的C語言標準和技術勘誤文檔,該標準被稱為C99。這里需要說明的是,與C89不同,并非市面上所有的編譯器都支持C99,并且有的編譯器只支持C99的部分新特性。相對于C89,C99主要做了以下幾方面的改進:

□ 增加了restrict與inline關鍵字。

□ 新增_Bool、_Complex與_Imaginary 3種數據類型,如C99中定義的復數類型為:float_Complex、float_Imaginary、double_Complex、double_Imaginary、long double_Complex與long double_Imaginary。

□ 增強數組的功能,支持可變長數組等。

□ 支持復合賦值。

□ 增強預處理程序,如引入_Pragma運算符,并增加了一些內部宏等。

□ 支持柔性數組結構成員,即允許結構中的最后一個元素是未知大小的數組。

由于技術的發展日新月異,因此雖然C99還沒有得到完全支持,但在2007年,標準委員會就又開始起草新的C語言標準來取代現有的C99標準,該標準命名為C1X,C1X是一個非正式名字。2011年12月,ANSI正式采納了ISO/IEC 9899:2011標準,即C11標準。相對于C99,C11主要做了如下幾方面的改進:

□ 采用新的對齊規范,包括_Alignas說明符、_Alignof運算符、aligned_alloc函數與<stdalign.h>頭文件。

□ 增加_Noreturn函數標記。

□ 增加_Generic關鍵詞。

□ 增加靜態斷言_Static_assert()。

□ 刪除gets()函數,C99中已經將此函數標記為過時,推薦新的替代函數gets_s()。

□ 采用新的fopen()模式。

□ 增加匿名結構體/聯合體。

□ 支持多線程技術,包括_Thread_local與頭文件<threads.h>。

□ 增加_Atomic類型修飾符和頭文件<stdatomic.h>。

□ 帶邊界檢查(bounds-checking)的函數接口,定義了新的安全的函數,例如fopen_s()、strcat_s()等。

□ 改進Unicode支持與頭文件<uchar.h>。

□ 增加quick_exit()函數作為第三種終止程序的方式。

□ 可以創建復數的宏。

□ 增加更多處理浮點數的宏。

□ struct timespec成為time.h的一部分,以及宏TIME_UTC和函數timespec_get()。

綜上所述,可以用圖1-2來直觀地闡述C語言標準的發展歷程。

圖1-2 C語言標準的發展過程

在GCC編譯器中,針對不同版本的C語言標準,可以通過在命令行中使用“-std”選項來選擇所需要使用的C語言標準版本。

1)C89或者C90


-ansi
-std=c90
-std=iso9899:1990

2)C95


-std=iso9899:199409

3)C99


-std=c99
-std=iso9899:1999

4)C11


-std=c11
-std=iso9899:2011

5)除此之外,如果需要在GCC中使用C擴展,還可以通過如下參數形式實現:


C89或者C90:-std=gnu90
C99:-std=gnu99
C11:-std=gnu11

主站蜘蛛池模板: 宝应县| 高陵县| 泌阳县| 孝昌县| 北川| 东山县| 新乡市| 攀枝花市| 正镶白旗| 夏邑县| 曲水县| 女性| 玉屏| 神农架林区| 池州市| 富民县| 高要市| 肥西县| 榆中县| 南木林县| 哈密市| 朝阳市| 建水县| 凤台县| 肥城市| 昂仁县| 克拉玛依市| 托里县| 壤塘县| 宜兰市| 伊宁县| 安平县| 武宁县| 崇左市| 江永县| 太康县| 虎林市| 鞍山市| 孟连| 民权县| 永嘉县|