作者:劉欣;
來自:碼農翻身(id:coderising)


“哇塞,怎麼可能這麼簡單!”


當C語言老頭兒還是小夥子的時候,第一次見到了彙編,發出了這麼一聲感慨。


在C語言看來,這彙編的指令實在是太簡單了,簡單到了令人髮指的地步,只有這麼幾類指令:


數據傳輸類:

就是把數據從一個位置複製到另外一個位置,比如從內存到寄存器,或者從寄存器到內存, 或者從寄存器到寄存器。


算術和邏輯運算類:

無非就是加減乘除,AND, OR, 左移,右移


控制類:

比較兩個值,跳轉到某一個位置。


彙編老頭兒非常地驕傲, 他經常囂張地說:“別看我的指令這麼簡單,但是配合我的寄存器和內存, 卻能完成你們這些所謂的高級語言的所有功能!”


這寄存器是什麼鬼? C語言腦海中只有內存和指針,根本就沒有什麼寄存器的概念, 實際上,這是屬於CPU阿甘的,容量有限,但是速度超級快的存儲部件。

編程語言的巔峯


編程語言的巔峯


32位CPU寄存器

圖片來源: http://pascalturbo.net/cpu-registers/

數組

C看着彙編這單薄的小身板,想到自己那優雅的if , 漂亮的while, for ,還有那極爲重要的函數調用,心裏不由得泛起嘀咕:我的程序怎麼可能被編譯成這麼簡單的彙編?


雖然心裏有點瞧不上,但C小夥還是挺恭敬的:“前輩,在我這裏有個數組的概念,編譯成彙編是什麼樣?”


int num[10];

num[0] = 100;

num[1] = 200;


除了機器語言,那就屬彙編最老,連C語言的第一個編譯器都是用匯編寫的,當之無愧的前輩。


彙編老頭兒沒想到C小夥兒連這個問題都沒弄清楚,說道:“我這裏只認寄存器和內存,你這所謂數組,就是內存的一段連續的空間嘛,我只要知道開始地址就可以了。”



編程語言的巔峯


編程語言的巔峯



C小夥兒一看,好傢伙,連變量名num都不要了。 不過說得也是, 彙編老頭只要記住初始地址,順着地址就能找到所有東西。


“咦,這個什麼0x000083d0不就相當於我的指針麼? ”


“是啊,不過在我這裏,都是地址,忘掉指針吧!”

條件分支

C小夥又想到了自己的if else,在彙編中該怎麼處理?


if(x < y ){
return y - x;
} else {
return x -y ;
}


彙編老頭兒說:“你們這些高級語言啊,就愛搞複雜化,怎麼不用goto呢?”


C小夥說:“goto 被迪傑斯特拉認爲是有害的,會破壞結構化,不建議使用!”


“唉,簡單就是美,你們這些高級語言懂不了,我這裏很簡單,就是比較和跳轉指令,從一個地方跳到另外一個地方執行就行了。”


彙編老頭兒一遍感慨,一遍寫道:


我們假設

%eax 寄存器保存的是y的值,

%edx 寄存器保存的是x的值。


 cmpl %eax, %edx ; 比較x和y
jge .L1 ; 如果x >= y,跳轉到.L1處去執行
subl %edx,%eax ; 計算y-x,結果存到eax寄存器中
jmp .done ; 跳轉到.done標籤處
.L1:
subl %eax, %edx ; 計算 x-y
movl %edx, %eax ; 把結果存到eax寄存器中
.done: ; 計算結束,結果保存在eax寄存器中


(碼農翻身注:這個例子來源於《深入理解計算機系統》)


C小夥兒看了半天,終於搞明白了這段彙編程序的含義,這所謂的jge也就是做一個判斷,然後跳轉到特定位置去執行,就像是if 和 goto 的結合。


彙編老頭兒看到C小夥兒懂了, 問道:“你想想你的while 循環,for 循環,是不是if 和 goto 的包裝而已?”


C小夥兒想了一會:“確實是這樣!”

編程語言的巔峯


編程語言的巔峯



“這不就結了,我的彙編看起來簡單,但是卻能表達你所有的流程控制語句,不管什麼if else, while, for ,switch ,對吧?”


C小夥兒覺得彙編老頭兒說的都是歪理:“這goto是簡單,可是程序讀起來就非常複雜了啊!”


彙編老頭兒說:“你算是說道了點子上,所謂高級語言,主要是方便人類的編寫和閱讀的,是爲了提升人類的效率。 在我這裏,主要是讓CPU阿甘執行的,那傻小子,速度飛快,什麼也不懂,你只要告訴它指令就行,越簡單越好。”


沒想到CPU阿甘聽到了對它的嘲諷,不滿地說:“老夥計,又在背後說我的壞話,我執行了億萬條指令以後,早就悟出了程序的局部性原理,這你懂不懂?”


(碼農翻身注:詳情參見《CPU阿甘》)

函數調用

C小夥看到不能難倒彙編老頭兒,想到了自己可以定義函數,精神一振,問道:“函數調用你怎麼處理啊?”


int funcA(int a){
......
funcB(10)
......
}
int funcB(int b){
......
funcC();
......
}


看看,這funcA調用funcB, funcB又調用funcC,函數嵌套調用,你那簡單的指令能處理? C小夥兒心裏暗想。


彙編老頭兒不慌不忙:“你可算是問了一個有價值的問題,不過這也難不倒我,我需要內存配合一下就行了。”



編程語言的巔峯


編程語言的巔峯



“看到裏邊的棧幀沒有,每個棧幀都表示一個函數的調用!”


“那這棧幀中有什麼東西?” C小夥兒問道。


“細節太複雜,給你畫個示意圖看看吧!”



編程語言的巔峯


編程語言的巔峯



“不對啊,你這棧幀中有輸入參數,有返回值,可是沒有函數代碼啊?代碼去哪兒了?”


“真是幼稚! 這是運行時在內存中對函數的表達,那代碼肯定是在代碼段啊。” 彙編老頭兒嘲諷道。


代碼段的指令不斷被CPU阿甘執行,遇到函數調用,就建立新的棧幀,函數調用結束,棧幀就會銷燬,廢棄。然後返回上一個棧幀。


C小夥兒意識到自己犯了一個大錯誤,他老是想着代碼的靜態結構,而忽略了運行時的表示。

編程語言的巔峯

他急於挽回面子,趕緊給C++打電話求援:“兄弟,快過來,治一下這個彙編老頭兒!”


C++瞭解了事情的經過,說道:“兄弟,不行啊,別看我有class, 但是最終我也得變成過程化的程序,翻譯成彙編,和你是一樣一樣的。”


(碼農翻身注: 參見《面向對象聖經》)


“那Python呢, Java 呢?” C小夥兒有點氣急敗壞。


“他們更不行了,是虛擬機中的語言,他們連彙編老頭兒的面兒都見不着,再說那虛擬機也是用你老兄C語言寫的啊!”


C小夥呆住了,可不是,自己是很多系統級軟件和編程語言的基礎,已經非常貼近硬件了,自己治不了彙編老頭兒,別人肯定也不行啊。

C小夥兒又想到了應用層那複雜的業務邏輯,他們都是由Python,Java, JavaScript等高級語言編寫的,還用到了什麼OOD,設計模式,函數式,響應式編程...... 但是它們都是一層層的抽象,幫助程序員更好地編寫程序,在最底層,還是彙編啊。


他嘆了一口氣,對彙編老頭說:“前輩,我服了,您可真是編程語言的巔峯啊。”


“不敢當,還有一個語言比我更厲害!”


“是誰?”


“機器語言! 只有0和1!不信你看看這程序員專屬的鍵盤。”



編程語言的巔峯


編程語言的巔峯


相关文章