溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C語言中程序編譯系統(tǒng)的示例分析

發(fā)布時間:2022-03-01 09:13:34 來源:億速云 閱讀:152 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要介紹C語言中程序編譯系統(tǒng)的示例分析,文中介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們一定要看完!

程序的翻譯環(huán)境和執(zhí)行環(huán)境

在ANSI C的任何一種實現(xiàn)中,存在兩個不同的環(huán)境 :

第1種是翻譯環(huán)境,在這個環(huán)境中源代碼被轉(zhuǎn)換為可執(zhí)行的機器指令。

第2種是執(zhí)行環(huán)境 ,它用于實際執(zhí)行代碼。

一個.c的文件事如何變成.exe的可執(zhí)行文件的呢?下面這張圖片是一個大概的過程:

C語言中程序編譯系統(tǒng)的示例分析

編譯和鏈接

翻譯環(huán)境

C語言中程序編譯系統(tǒng)的示例分析

  • 組成一個程序的每個源文件通過編譯過程分別轉(zhuǎn)換成目標(biāo)代碼( object code )。

  • 每個目標(biāo)文件由鏈接器( linker )捆綁在一 起,形成一個單一-而完整的可執(zhí)行程序。

  • 鏈接器同時也會引入標(biāo)準(zhǔn)C函數(shù)庫中任何被該程序所用到的函數(shù),而且它可以搜索程序員個人的程序庫,將其需要的函數(shù)也鏈接到程序中。

編譯的幾個階段

接下來,我來用Linux平臺來給大家演示一下編譯的三個過程:

我們先編寫一個簡單C程序:

C語言中程序編譯系統(tǒng)的示例分析

然后執(zhí)行這樣一句指令:

gcc test.c

這句指令是讓gcc這個編譯器來編譯我們的代碼,執(zhí)行完這句指令我們會發(fā)現(xiàn)會生成一個a.out這樣一個可執(zhí)行文件,

C語言中程序編譯系統(tǒng)的示例分析

我們執(zhí)行再下面這樣一句指令:

./a.out

這樣我們就可以執(zhí)行這個可執(zhí)行文件了,

C語言中程序編譯系統(tǒng)的示例分析

為了讓大家更好地感受到編譯的過程,我們來一步一步看:

預(yù)處理

我們執(zhí)行再下面這樣一句指令,讓代碼預(yù)處理完之后就停下來:

gcc -E test.c -o test.i

這句指令的意思就是把預(yù)處理完之后的信息輸出到一個test.i的文件中。

C語言中程序編譯系統(tǒng)的示例分析

可以發(fā)現(xiàn)的是,這里多了一個test,i的文件,我們可以打開看一看:

C語言中程序編譯系統(tǒng)的示例分析

可以發(fā)現(xiàn)的是,有三個點發(fā)生了變化:

  • 頭文件被展開

  • 宏被文本替換了

  • 注釋被刪除了

我們對原代碼做一個處理,不包含stdio.h的頭文件,我們自己寫一個頭文件:

C語言中程序編譯系統(tǒng)的示例分析

再來看一下,預(yù)處理后的文件是什么樣子的:

C語言中程序編譯系統(tǒng)的示例分析

效果通上面一樣。

所以預(yù)處理的幾個動作

  • 頭文件的包含

  • 預(yù)處理指令的完成(eg:#define、#pragma…)

  • 注釋的刪除

編譯

執(zhí)行再下面這樣一句指令讓文件進(jìn)行編譯形成匯編代碼:

gcc -S test.c

C語言中程序編譯系統(tǒng)的示例分析

執(zhí)行完之后就可以生產(chǎn)出一個test.s的文件,我們可以打開看一看:

C語言中程序編譯系統(tǒng)的示例分析

這里其實就是匯編代碼。

所以編譯的幾個動作

  • 語法分析

  • 詞法分析

  • 語義分析

  • 符號匯總

符號匯總: 符號匯總的都是全局的符號。例如上面我們的代碼頭文件就匯總了一個Add,.c文件就匯總的一個Add和main。

匯編

接下來我們執(zhí)行這樣一條指令:

gcc -c test.c

對源文件進(jìn)行匯編,結(jié)果生成了一個test.o的目標(biāo)文件:

C語言中程序編譯系統(tǒng)的示例分析

打開這個文件,我們會發(fā)現(xiàn)這是一個我們看不懂的二進(jìn)制文件:

C語言中程序編譯系統(tǒng)的示例分析

所以其實匯編是把匯編代碼轉(zhuǎn)換為二進(jìn)制代碼(機器指令)。

這個過程還做了一件件事——形成符號表

C語言中程序編譯系統(tǒng)的示例分析

鏈接

鏈接做的兩個事情

  • 合并段表

  • 符號表的合并和符號表的重定位

在Linux系統(tǒng)下,test.o二進(jìn)制文件是用一個elf這樣的格式來組織文件的。

elf會把文件組織成一個段。test.o和Add.o都有一個段,那么我們怎樣才能看懂elf格式的文件呢?

我們有這樣一個工具叫做readelf,他可以看懂這樣一個文件,所以我們輸入這樣一條指令:

readelf test.o -a

C語言中程序編譯系統(tǒng)的示例分析

我們就確實可以看到這樣一個段的存在。

C語言中程序編譯系統(tǒng)的示例分析

然后這下面還有符號表的匯總:

C語言中程序編譯系統(tǒng)的示例分析

其實a.out這個文件也是elf格式的,所以其實鏈接就是把這幾個elf格式的文件的段表合并,然后test中的Add函數(shù)就有了地址。

C語言中程序編譯系統(tǒng)的示例分析

運行環(huán)境

程序執(zhí)行的過程:

  • 程序必須載入內(nèi)存中。在有操作系統(tǒng)的環(huán)境中:一般這個由操作系統(tǒng)完成。在獨立的環(huán)境中,程序的載入必須由手工安排,也可能是通過可執(zhí)行代碼置入只讀內(nèi)存來完成。

  • 程序的執(zhí)行便開始。接著便調(diào)用main函數(shù)。

  • 開始執(zhí)行程序代碼。這個時候程序?qū)⑹褂靡粋€運行時堆棧(stack),存儲函數(shù)的局部變量和返回地址。程序同時也可以使用靜態(tài)(static)內(nèi)存,存儲于靜態(tài)內(nèi)存中的變量在程序的整個執(zhí)行過程一直保留他們的值。

  • 終止程序。正常終止main函數(shù);也有可能是意外終止。

以上是“C語言中程序編譯系統(tǒng)的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI