Windows Firefox 程序员 微软 Python mysql 编程 php nginx apache google linux 云计算 开源 centos Ubuntu Android shell java wordpress

《C語言編程魔法書:基於C11標準》——第一篇 預備知識篇 第1章 C魔法概覽1.1 例說編程語言

第一篇 預備知識篇

第1章 C魔法概覽

本章內容主要對C編程語言(以下簡稱C語言)進行大體介紹,包括它的歷史以及C語言標準的演化進程。然後介紹一下C語言編程思想,當前主流C語言編譯器以及GNU語法擴展。最後簡單介紹一下從用C語言編寫程序到編譯、構建一個可執行程序的大致過程。
計算機編程語言從對計算機硬件底層的抽象程度進行分類,可分為:機器語言、匯編語言以及高級語言。下面由底層到高層分別介紹這幾種類別的編程語言。

1.1 例說編程語言

1)機器語言是直接通過十六進制數表示當前處理器架構的機器指令碼。指令碼包含了當前指令的功能(比如算術邏輯運算、移位、分支、中斷、I/O等)、寄存器、立即數等多種元素。每種處理器架構所對應的機器碼的字節長度也各不相同,有些是固定長度的(比如ARM、MIPS等架構),有些是可變長度的(比如x86架構)。
2)匯編語言(Assembly Language)通過簡單的指令助記符(memonics)來表示對應機器指令的功能、寄存器編號、立即數(immediates)等元素。匯編語言是對機器指令的簡單抽象,通過匯編器(assembler)可以將匯編語句翻譯成對應的機器指令碼。
3)高級語言的表達形式更為抽象且貼近我們日常的語言表述。而且,高級語言比起匯編語言往往更具有表達力,且擁有更加豐富的語法特性,以便將程序進行結構化和模塊化。比如,高級語言具有自定義變量標識符、自定義數據結構、分支與循環、更形象自然的表達式等。高級語言一般通過編譯器(compiler)可直接將表達式翻譯為對應的機器指令碼;也可以將高級語言先翻譯為中間語言(類似於匯編,但可能比匯編適用範圍更廣、更利於跨平臺的字節碼),最後將中間語言翻譯為最終的機器指令碼。
當然,有些書中還介紹了第四代語言,它基於高級語言,比高級語言更抽象,只需要一些簡單的描述語句就能讓計算機做比較復雜的工作。比如SQL(結構化查詢語言,用於數據庫查詢)算是一種第四代語言。
下面,為了能讓大家對這三種層次的編程語言有一個感性的認識,這裏將列舉ARMv8架構處理器下的機器語言、匯編語言,加上它們相應的C語言。讀者如果手頭有Xcode,並且有包含Apple A7或更高版本處理器的iOS設備的話,可以直接編譯運行,並能看到最終效果。
下面首先列出一個文件名為my_sub.s的匯編源文件,其中包含了機器語言和匯編語言。見代碼清單1-1:

代碼清單1-1 機器語言與匯編語言


.text
.align 4

#ifdef __arm64__

.globl _my_sub_machine
.globl _my_sub_assembly

// 用机器语言实现减法操作
_my_sub_machine:

    .long 0x4b010000

    .long 0xd65f03c0

// 用汇编语言实现减法操作
_my_sub_assembly:

    sub w0, w0, w1

    ret

#endif

在代碼清單1-1中,_my_sub_machine程序片段中的兩條.long語句即為機器指令。這兩條機器指令正好與_my_sub_assembly中的兩條匯編指令相對應。也就是說,“0x4b010000”這串32位的十六進制代碼意思就是“sub w0, w0, w1”,表示將寄存器w0與寄存器w1的值進行相減,然後將結果寫回w0寄存器中。而“0xd65f03c0”指令碼對應於“ret”(更確切地說是ret x30),表示返回當前過程(procedure)。在匯編語言中,一般會使用過程或者例程(routine)來表示一個可執行的程序片段。在C語言中一般都用函數(function)表示。我們在這裏能夠明顯看到,匯編語言采用指令助記符的方式比寫機器指令碼要直觀得多,而且也不容易出錯。“sub”指令的功能從助記符上就能知道是“減法”功能;而w0、w1也明確指明了使用的寄存器是w0和w1。這些在“0x4b010000”這種機器指令碼上都無法直觀地表現出來。
代碼清單1-2列出C語言是如何表達一個減法操作的。

代碼清單1-2 減法操作對應的C語言


static int my_sub_c(int a, int b)
{
    return a - b;
}

代碼清單1-2所列出的C語言代碼與代碼清單1-1中的機器指令碼和匯編語言完全對應,意思一目了然——將參數變量a的值與參數變量b的值進行相減,然後將結果返回。從這裏我們就能看到機器語言、匯編語言以及以C語言為代表的高級語言之間在表達力上的差距了。高級語言的目的就是為了給程序員提供更良好的編程工具,更簡潔、更富有表達力的語言,使得我們程序員能提升生產力,並且能構思出更多精彩炫酷的應用,而不是把太多的精力都投入在如何讓計算機執行的細節上。
代碼清單1-3能讓我們在主函數或其他函數中測試上述已經編寫好的函數。

代碼清單1-3 展示減法操作的結果


#ifdef __arm64__

extern int my_sub_machine(int a, int b);
extern int my_sub_assembly(int a, int b);

int result_machine = my_sub_machine(10, 2);
int result_assembly = my_sub_assembly(5, 3);
int result_c = my_sub_c(6, 2);

printf("Three results: %d, %d, %d\n", result_machine, result_assembly, result_c);

#endif

執行了上述代碼之後,我們最後能在控制臺看到輸出結果:“Three results: 8, 2, 4”。可見,上述三種不同的編程語言,計算功能是完全一致的,都是對兩個輸入參數做減法操作,然後返回差值。然而就可讀性、可理解性以及編程便利性而言,顯然C語言比起其他兩者要強得多。而可讀性最差的無疑就是機器指令碼了。
1.C語言的類別與產生
對於高級語言來說,從表達上又可分為命令式編程語言(imperative programming language)和陳述型編程語言(declarative programming language)。命令式語言主要包括過程式(procedural)、結構化(structured)以及面向對象(object-oriented)的編程語言;陳述型編程語言主要包括函數式(functional)以及邏輯型(logical)編程語言。而C語言則屬於結構化的命令式編程語言。不過現在很多命令式編程語言也包含了一些函數式編程語言的特征。在本書中,後面第18章中談到的Blocks語法就是一個很典型的函數式編程語言的語法。
C語言最初由Dennis Ritchie於1969年到1973年在at&T貝爾實驗室裏開發出來,主要用於重新實現Unix操作系統。此時,C語言又被稱為K&R C。其中,K表示Kernighan的首字母,而R則是Ritchie的首字母。K&R C語言與後來標準化的C語言有很大差異。比如,如果函數返回類型為int,則int可省:int my_function() { },也可以寫成my_function(){ }。編譯器不會有任何警告,更不會報錯。另外,還有現在看來比較奇葩的函數定義,像我們現在定義這麽一個函數——void my_function(int a, char p){ },如果是用K&R C語法定義的話要寫成:void my_function(a, p) int a; char p; { }。K&R的C語法中,定義一個函數時,其形參列表先列出形參的標識符,然後在函數聲明的後面緊跟著對形參標識符的完整聲明,最後是函數體。這在現行標準中已經被逐步廢棄使用了。另外,當時的第一本C語言專業書《The C Programming Language》也並非一個正式的編程語言規範,但被用了許多年。
2.C90標準
由於C語言被各大公司所使用(包括當時處於鼎盛時期的IBM PC),因此到了1989年,C語言由美國國家標準協會(ANSI)進行了標準化,此時C語言又被稱為ANSI C。而僅過一年,ANSI C就被國際標準化組織ISO給采納了。此時,C語言在ISO中有了一個官方名稱——ISO/IEC 9899:1990。其中,9899是C語言在ISO標準中的代號,像C++在ISO標準中的代號是14882。而冒號後面的1990表示當前修訂好的版本是在1990年發布的。對於ISO/IEC 9899:1990的俗稱或簡稱,有些地方稱為C89,有些地方稱為C90,或者C89/90。不管怎麽稱呼,它們都指代這個最初的C語言國際標準。這個版本的C語言標準作為K&R C的一個超集(即K&R C是此標準C的一個子集),把後來引入的許多非官方特性也一起整合了進去。其中包括了從C++借鑒的函數原型(Function Prototypes),指向void的指針,對國際字符集以及本地語言環境的支持。在此標準中,盡管已經將函數定義的方式改為現在我們常用的那種方式,不過K&R的語法形式仍然兼容。
3.C99標準
在隨後的幾年裏,C語言的標準化委員會又不斷地對C語言進行改進,到了1999年,正式發布了ISO/IEC 9899:1999,簡稱為C99標準。C99標準引入了許多特性,包括內聯函數(inline functions)、可變長度的數組、靈活的數組成員(用於結構體)、復合字面量、指定成員的初始化器、對IEEE754浮點數的改進、支持不定參數個數的宏定義,在數據類型上還增加了long long int以及復數類型。毫不誇張地說,即便到目前為止,很少有C語言編譯器是完整支持C99的。像主流的gcc以及Clang編譯器都能支持高達90%以上,而微軟的Visual Studio 2015中的C編譯器只能支持到70%左右。
4.C11標準
2007年,C語言標準委員會又重新開始修訂C語言,到了2011年正式發布了ISO/IEC 9899:2011,簡稱為C11標準。C11標準新引入的特征盡管沒C99相對C90引入的那麽多,但是這些也都十分有用,比如:字節對齊說明符、泛型機制(generic selection)、對多線程的支持、靜態斷言、原子操作以及對Unicode的支持。本書將主要針對C11標準為大家詳細講解C編程語言
筆者近兩年也是在不斷地了解C語言標準委員會的最新動態,其中看到有人提出想為C語言添加面向對象的特性,包括增加類、繼承、多態等已被C++語言所廣泛使用的語法特性,但是最終被委員會駁回了。因為這些復雜的語法特性並不符合C語言的設計理念以及設計哲學,況且C++已經有了這些特性,C語言無需再對它們進行支持。筆者將在第19章給大家談談C語言設計理念與發展方向。

延伸阅读

    评论