c文件是源碼文件颜说。里面的書(shū)寫(xiě)是相對(duì)來(lái)說(shuō),最接近人類(lèi)語(yǔ)言的C語(yǔ)言汰聋。
我們使用gnu工具鏈來(lái)使之生成二進(jìn)制文件门粪。然后,計(jì)算機(jī)機(jī)器就可以執(zhí)行它烹困。
也許你認(rèn)為很簡(jiǎn)單玄妈,只需要執(zhí)行g(shù)cc hell.c就可以生成二進(jìn)制文件了,而如果你使用的是IDE集成開(kāi)發(fā)環(huán)境的話髓梅,那么拟蜻,也許更簡(jiǎn)單,只需要編譯構(gòu)建就可以了枯饿。然而瞭郑,事實(shí)并非如此簡(jiǎn)單。以上過(guò)程鸭你,可以分解為4個(gè)步驟屈张,分別是:
1. 預(yù)處理prepressing
2. 編譯compilation
3. 匯編assembly
4. 鏈接linking
預(yù)編譯
首先是源代碼hello.c和相關(guān)的頭文件,如stdio.h等被預(yù)編譯器cpp預(yù)編譯成一個(gè).i文件袱巨。
預(yù)編譯過(guò)程主要處理那些源代碼文件中的以‘#’開(kāi)始的預(yù)編譯指令阁谆。比如“#include”、“#define”等愉老,具體規(guī)則如下:
1. 將所有的“#define”刪除场绿,并展開(kāi)所有的宏定義。
2. 處理所有條件預(yù)編譯指令嫉入,比如“#if焰盗、#ifdef、#elif咒林、#else熬拒、#endif”等。
3. 處理“#include”預(yù)編譯指令垫竞,將被包含的文件插入到該預(yù)編譯指令的位置澎粟。注意,這個(gè)過(guò)程是遞歸進(jìn)行的欢瞪,也就是說(shuō)被包含的文件可能還包含其他文件活烙。
4. 刪除所有的注釋/**/、//遣鼓。
5. 添加行號(hào)和文件名標(biāo)識(shí)啸盏。比如# 2 "hello.c" 2。以便于編譯時(shí)編譯器產(chǎn)生調(diào)試用的行號(hào)信息及用于編譯時(shí)產(chǎn)生編譯錯(cuò)誤或警告時(shí)能夠顯示行號(hào)骑祟。
6. 保留所有的#pragma編譯器指令回懦,因?yàn)榫幾g器需要使用它气笙。
經(jīng)過(guò)預(yù)編譯后的.i文件不包含任何宏定義,因?yàn)樗械暮暌呀?jīng)被展開(kāi)粉怕,并且包含的文件也已經(jīng)被插入到.i文件中健民。所以當(dāng)我們無(wú)法判斷宏定義是否正確或頭文件是否包含正確時(shí)抒巢,可以查看預(yù)編譯后的文件來(lái)確定問(wèn)題贫贝。
編譯
編譯過(guò)程就是把預(yù)處理完的文件進(jìn)行一系列詞法分析、語(yǔ)法分析蛉谜、語(yǔ)義分析及優(yōu)化后生成相應(yīng)的匯編代碼文件稚晚,這個(gè)過(guò)程往往是我們所說(shuō)的整個(gè)程序構(gòu)建的核心部分犁珠,也是最復(fù)雜的部分之一缓熟。
現(xiàn)在版本的gcc把預(yù)編譯和編譯兩個(gè)步驟合成一個(gè)步驟姑子,使用一個(gè)叫做cc1的程序來(lái)完成這兩個(gè)步驟筋讨。
對(duì)于C語(yǔ)言來(lái)說(shuō)塔插,這個(gè)預(yù)編譯和編譯程序是cc1劫瞳,對(duì)于c++來(lái)說(shuō)和媳,這個(gè)程序是cc1plus巴刻,Java是jc1涵紊。所以傍妒,實(shí)際上gcc這個(gè)命令指示這些后臺(tái)程序的包裝,它會(huì)根據(jù)不同的參數(shù)要求去調(diào)用相應(yīng)的預(yù)編譯編譯程序cc1摸柄、匯編器as颤练、鏈接器ld。
匯編
匯編器是將代碼轉(zhuǎn)變成機(jī)器可以執(zhí)行的指令驱负,每一個(gè)匯編語(yǔ)句幾乎都對(duì)應(yīng)一條機(jī)器指令嗦玖。所以匯編器的匯編過(guò)程相對(duì)于編譯器來(lái)講比較簡(jiǎn)單,它沒(méi)有復(fù)雜的語(yǔ)法跃脊,也沒(méi)有語(yǔ)義宇挫,也不需要做指令優(yōu)化,只是根據(jù)匯編指令和機(jī)器指令的對(duì)照表一一翻譯就可以了酪术,“匯編”這個(gè)名字也來(lái)源于此捞稿。上面的匯編過(guò)程我們可以使用匯編器as來(lái)完成。
鏈接
鏈接是一個(gè)難點(diǎn)拼缝,怎么鏈接娱局,鏈接過(guò)程到底做了什么,都是揮之不去的疑惑咧七!
可以看到衰齐,我們需要將一大堆文件鏈接起來(lái)才可以得到“a.out”,即最終的可執(zhí)行文件继阻。其中-lgcc -lgcc_eh –lc這些都是什么參數(shù)耻涛?crt1.o废酷、crti.o、crtbeginT.o抹缕、crtend.o澈蟆、crtn.o這些文件是什么?為何要將它們和hello.o連接起來(lái)才可以得到可執(zhí)行文件卓研?請(qǐng)看鏈接一文趴俘。。奏赘。
摘抄自《程序員的自我修養(yǎng)》