一臺IBM的Plugboard程序員
一、咱們拿一小段真實的 C 語言程序來看看。sass
[root@luoahong c]# cat test.c int main() { int a = 1; int b = 2; a = a + b; }
二、要讓這段程序在一個 Linux 操做系統上跑起來,咱們須要把整個程序翻譯成一個彙編語言bash
[root@luoahong c]# gcc -g -c test.c [root@luoahong c]# objdump -d -M intel -S test.o
三、在一個 Linux 操做系統上,咱們能夠簡單地使用 gcc 和 objdump 這樣兩條命令,把對應的彙編代碼和機器碼都打印出來。函數
[root@luoahong c]# objdump -d -M intel -S test.o test.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <main>: int main() { 0: 55 push rbp 1: 48 89 e5 mov rbp,rsp int a = 1; 4: c7 45 fc 01 00 00 00 mov DWORD PTR [rbp-0x4],0x1 int b = 2; b: c7 45 f8 02 00 00 00 mov DWORD PTR [rbp-0x8],0x2 a = a + b; 12: 8b 45 f8 mov eax,DWORD PTR [rbp-0x8] 15: 01 45 fc add DWORD PTR [rbp-0x4],eax } 18: 5d pop rbp 19: c3 ret
咱們實際在用 GCC(GUC 編譯器套裝,GUI CompilerCollectipon)編譯器的時候,能夠直接把代碼編譯成機器碼呀,操作系統
爲何還須要彙編代碼呢?緣由很簡單,你看着那一串數字表示的機器碼,是否是摸不着頭腦?可是即便你沒有學過彙編代碼,翻譯
看的時候多少也能「猜」出一些這些代碼的含義。由於彙編代碼其實就是「給程序員看的機器碼」,也正由於這樣,機器碼和彙編代碼是一一對應的。3d
從高級語言到彙編代碼,再到機器碼,就是一個平常開發程序,最終變成了 CPU 能夠執行的計算機指令的過程。orm
你可能一會兒記不住,或者對這些指令的含義還不能一會兒掌握,這裏我畫了一個表格,給你舉例子說明一下,幫你理解、記憶。blog
爲了讀起來方便,咱們通常把對應的二進制數,用 16 進製表示出來。在這裏,也就是0X02324020。這個數字也就是這條指令對應的機器碼。遞歸
回到開頭咱們說的打孔帶。若是咱們用打孔表明 1,沒有打孔表明 0,用 4 行 8 列表明一條指令來打一個穿孔紙帶,那麼這條命令大概就長這樣:
到這裏,想必你也應該明白了,咱們在這一講的開頭介紹的打孔卡,其實就是一種存儲程序型計算機。
只是這整個程序的機器碼,不是經過計算機編譯出來的,而是由程序員,用人腦「編譯」成一張張卡片的。對應的程序,也不是存儲在設備裏,而是存儲成一張打好孔的卡片。
可是整個程序運行的邏輯和其餘 CPU 的機器語言沒有什麼分別,也是處理一串「0」和「1」組成的機器碼而已
這一講裏,咱們看到了一個 C 語言程序,是怎麼被編譯成爲彙編語言,乃至經過彙編器再翻譯成機器碼的。
除了 C 這樣的編譯型的語言以外,不論是 Python 這樣的解釋型語言,仍是 Java 這樣使用虛擬機的語言,其實最終都是由不一樣形式的程序,把咱們寫好的代碼,轉換成 CPU 可以理解的機器碼來執行的。
只是解釋型語言,是經過解釋器在程序運行的時候逐句翻譯,而 Java 這樣使用虛擬機的語言,則是由虛擬機對編譯出來的中間代碼進行解釋,或者即時編譯成爲機器碼來最終執行。
然而,單單理解一條指令是怎麼變成機器碼的確定是不夠的。接下來的幾節,我會深刻講解,包含條件、循環、函數、遞歸這些語句的完整程序,是怎麼在 CPU裏執行的