1. 程式人生 > >【讀圖學C語言】編譯時發生了什麼?

【讀圖學C語言】編譯時發生了什麼?

編譯過程為預處理,編譯(.s檔案),優化,彙編(.o檔案),連結(生成可執行檔案)

-c 生成.o檔案,也就是二進位制檔案

-S 生成.s檔案 也就是彙編檔案

一、你知道編譯的時候發生了什麼嗎?

你知道C語言編譯時發生了什麼嗎?

是不是像我一樣嫌棄老師上課講的冗長又抽象,搞什麼嘛!

說那麼多還不如把細節展示給我看!

這周的Shorts視訊中有一集叫做Compilers,7分鐘不僅詳細講了編譯時的四個步驟,還開啟查看了 -E -S -c之後的檔案。看完感到極大的滿足,於是動手試了一遍,下面把視訊轉換成圖文,跟我一起學C語言啦!

首先,寫一個大家非常熟悉的"hello world!"程式碼

哦,我用的編輯器是emacs,作業系統是ubuntu(linux),然後直接在終端(Terminal)下用gcc編譯,然後 ./a.out 執行。執行正常

這就完成了一次編譯到執行的操作。平時我做作業也都是這樣,並沒有理會從C語言到機器語言的編譯過程具體是什麼樣。

二、編譯的四個步驟

gcc的編譯流程分為四個步驟,分別為:

・ 預處理(Pre-Processing)
・ 編譯(Compiling)
・ 彙編(Assembling)
・ 連結(Linking)

(1)編譯預處理(Pre-Processing)

先輸入這一行命令:gcc -E 目標檔案.c

回車後就被刷屏了....

把這些程式碼匯入到一個hello2.c的檔案中

開啟後

這是什麼鬼!長這麼奇怪= =

哈,居然有800多行,拉到最後終於看到熟悉的 "hello world!"程式碼片段惹!

這就是編譯預處理啦~ 搜了一下什麼是編譯預處理

【摘】預編譯的主要作用如下:

●將原始檔中以”include”格式包含的檔案複製到編譯的原始檔中。
●用實際值替換用“#define”定義的字串。
●根據“#if”後面的條件決定需要編譯的程式碼。

是嘛~剛剛刷屏那個就是把原始碼中 #include <stdio.h> 這一行替換成了834行程式碼..

再拿巨集定義試試,注意第3行

相同操作之後,對比預處理之後的.c檔案

喏,836行之前沒有區別!只有原來 #define name "Jenny" 那一行消失了,取而代之的是原始碼中 printf("Hello %s\n",name); 中的name 被換成了 "Jenny" 

這就是傳說中的,define只做“文字替換”啦

(2)編譯(Compiling)

下面用 gcc -S 目標檔案.c 來編譯,用C語言程式碼 生成 組合語言

開啟編譯後的 hello.s 檔案

又是什麼鬼,完全看不懂....

(3)彙編(Assembling)

用 gcc -c 目標檔案.s 把

開啟 hello.o二進位制檔案

這就是傳說中的機器碼了,你看到中間的 "hello world!" 了嗎?

*Bonus 直接修改二進位制檔案

讓我們改改機器碼試試!→_→

改成 no zuo no die ....

執行試試

玩壞了 ..>_<.. 一定是位元組不一樣!!

改成hello jenny

這樣就行啦!

*Bonus 用十六進位制看機器碼!

哈哈哈,有點像傳說中的10101010串了吧!我不知道怎麼通過二進位制檢視機器碼....

再改成nozuonodie!!

這次成功了

(4) 連結(Linking)

剛剛一直到這個步驟,其實程式碼都不能執行。可執行檔案 a.out 是我之前一步gcc hello.c生成的。

最後一步連結,需要在二進位制檔案 hello.o 的基礎上,生成可執行檔案 .out 

命令為 gcc hello.o

列出當前資料夾下面的檔案,可以發現只有 hello.out 是綠色的,並且最左邊一堆rwx裡面只有hello.out帶有x,那些rwx表示的是"read","write","execute"的許可權啦!