一串**從寫入編譯器到最後被執行,到底中途經歷了什麼?
c語言中有乙個經典的例子helloworld,這是每乙個程式設計師踏入程式設計之路的第一步,哈哈,一入佛門深似海,從此節操是路人。
剛開始我們很懵,不知道什麼,也不敢多問,可是學習了很久之後,你發現你的問題變得多了,為什麼就會被編譯器給列印出來hello world?為什麼必須這樣子寫才能被執行出來hello world?怎麼存放,怎麼執行?等等,你就是乙個十萬個為什麼了。
#include
int main()
好簡單的**,相信你是閉著眼睛都能寫出來的。這不是重點,重點是怎麼執行出來的,解決你的為什麼。
這個**被寫出來,然後被gcc -o hello hello.c 就可以執行了,哇!真的執行出來了helloworld。剛開始你也會覺得很神奇,但是見多了就覺得沒那麼新奇了。
其實看著很簡單的**,可是對於編譯器來說它是怎麼處理的呢?
事實上,上述的過程被分解成了4個部分,分別是預處理、編譯、彙編和鏈結。
那就一步一步來,反正一口也是吃不了乙個胖子的。
剛開始#include是被當成了一種慣性來寫出來的。它是什麼,為什麼用?預處理可是專門為它量身打造。
預處理階段stdio.h被預編譯成乙個.i的檔案,對於c++程式來說,源**是.cpp結尾,標頭檔案是.hpp結尾的,那麼被預編譯以後成了.ii。
linux經常使用的命令是:gcc -e hello -o hello.i
預編譯主要的工作(處理以#開頭的預編譯指令):
1.展開所有#define定義的巨集;
2.處理所有的條件預編譯指令,如:」if「,」ifdef」,」elif」,」else」,」endif」.
3.#include包含的檔案按插入到檔案指定的位置。
4.刪除注釋
5.新增行號
6.保留#pragme的預編譯指令。
編譯就是就接著預處理的檔案,進行詞法分析、語法分析、語義分析、優化**、檢查錯誤、彙總所有的符號。
linux的指令 :gcc -s hello.i -o hello.s
根據編譯完之後的.s檔案,將.s檔案轉變成彙編指令。
linux指令:gcc -c hello.c -o hello.o
經過彙編後變成了.o檔案。
大致畫圖說明一下,前面發生的事情。
那麼這個二進位制可重定向的二進位制檔案,是什麼樣子感覺很神奇呀!沒事神秘還是要有的,一會在說。
從此之後hello變成了可執行檔案。
二進位制可重定向目標檔案
目標檔案:
紅色部分是和二進位制可重定向目標檔案的區別:
回歸到原來的主幹道上吧!不要迷路了!
將目標問價載入到虛擬位址空間之後,將main函式的入口位址寫入pc暫存器。
還沒有執行,目標檔案被載入都了自己的虛擬位址空間。但是作業系統不認識這個虛擬位址呀!
我們得大費周章的載入到物理記憶體,讓作業系統認識它。怎麼載入呢,大致是這樣子的。
這下子作業系統才認識,hello才會被執行,現在看來,是不是乙個helloworld要被執行,也是很費勁的,沒你想得那麼簡單。
所以好好愛惜你的作業系統吧!
編譯鏈結執行原理 編譯鏈結執行過程
乙個.c cpp源程式檔案要最後變成.exe windows 或者.out linux 可執行檔案,要經過編譯和鏈結過程。四個步驟 預編譯,編譯,彙編,連線 一 預編譯 處理以 開頭的預編譯指令,比如 include,define等,規則如下 1 刪除所有的 define,並展開所有的巨集替換 文字...
編譯鏈結執行原理
預編譯.i 刪除 define 文字替換 處理 include 遞迴展開 處理 if end if等預編譯指令 刪除注釋 新增行號和檔案標識 保留 pragma 編譯.s 1.詞法分析 2.語法分析 3.語義分析 4.優化 5.生成彙編指令 低階語言 以下是彙編指令的 int main 彙編.o 翻...
編譯鏈結原理 總述 編譯階段 鏈結階段 執行原理
在平常的應用程式開發過程中,我們很少需要關注編譯和鏈結的過程,因為通常都是在整合的開發環境下執行,因此一般編譯和鏈結都是一步完成,通常將這種編譯和連線合併到一起的過程稱為構建。這樣雖然簡便,但是在這整個過程中,有時出現問題時,我們只能看到問題的表現,而很難看清本質性問題,所以對於這些一步完成的操作背...