更新時間:2025-03-21 15:20:18作者:佚名
誰叫我的主
現在最重要的是要跟上趨勢,因此,如果您使用更時尚的單詞,誰會觸及我的奶酪。誰叫我的主人?但是,作為計算機工作人員,我建議每個人不要遵循趨勢。 Java今天很受歡迎,.NET明天很受歡迎,因此請學習任何時尚的東西。我的意思是花幾年時間來學習基本技能,當您遵循趨勢時,您將能夠以一半的努力取得兩倍。不再胡說八道。
我們都聽到這樣的說法:“主要是C語言的入口”。我仍然不明白為什么我這么說。就像有人說:“賺錢正在接女孩,”他一定被無數磚頭打了一巴掌。這句話應該是“賺錢是接女孩的條件,但是這種情況尤其重要。”那么上面的句子應該是“主要是C語言中的符號,但此符號非常特別。”
讓我們看以下示例:
/ *文件名test00.c */
int main(int argc,char* argv)
返回0;
編譯并鏈接它:
cc test00.c -o test.exe
test.exe將生成
但是我們添加了此選項:-nostdlib(不鏈接到標準庫)
cc test00.c -nostdlib -o test.exe
鏈接器將報告一個錯誤:
未定義的符號:__ -start
也就是說:
1。編譯器默認值以找到__啟動符號,而不是主要的符號
2。符號__ -start是程序的起點
3。主是標準庫調用的符號
讓我們考慮另一個問題:
當我們編寫一個程序(例如模塊)時,我們通常需要初始化和去定位,但是為什么有些模塊在編寫C程序時沒有這兩個過程?例如,我們的程序可以雜亂無章,沒有主機,但我們不會在Main中初始化堆。例如,您可以直接在Main中打印F,但是我們沒有打開標準輸出文件。 (那些不知道stdin,stdout,stderr和printf和stdout關系的人,請先查看C語言中文件的概念)。
有人說這些事情不需要初始化。如果您真的必須這樣想,請不要再讀任何內容。我個人認為計算機軟件不適合您。
聰明的人會認為他們必須在主要領先之前做過一些事情。直接調用這些功能而無需初始化。通常,我們會在編譯器環境中找到一個類似于CRT0.O的名稱的文件,該名稱包含我們剛才提到的__ -start符號。 (CRT可能是C運行時的縮寫,請幫助確認。)
那么,真正的CRT0.S是什么樣的?在這里,我們給出一些偽代碼:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
部分.TEXT:
__開始:
init stack;
初始化堆;
開放性stdin;
打開stdout;
開放式stderr;
推動argv;
推動argc;
致電_main; (呼叫主)
貧困堆;
關閉stdin;
關閉stdout;
關閉stderr;
致電__ exit;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
實際上,可能有很多初始化工作,因為它們都與操作系統有關,因此作者不會一個一個列出它們。
注意:
1。不同的編譯器不一定具有默認符號__ -start。
2。_組裝中的詞是C語言中的主要內容,因為匯編器和C編譯器具有不同的命名符號(通常是一個下劃線'_')。
3。目前,操作系統結構的兩個主要分支:微核和麥克羅內爾。微動物的優點是它們具有清晰的結構和簡單的結構,較少的內核組件,易于維護;缺點是流程之間存在更多的溝通,程序經常進入和退出內核,并且其效率較低。宏內核恰恰相反。目的是什么:無法確保在用戶空間中初始化每個組件(標準庫功能)。某些組件可能不會初始化。創建過程時,操作系統在內核空間中進行操作。這取決于操作系統的特定實現。例如,堆,宏內核結構可以在內核中初始化,并且微核結構可以在用戶空間中。即使是相同的微核,也可以在內核空間中初始化此東西。
隨著CPU技術的發展,存儲量的迅速擴展和代碼復雜性的增加,微動物越來越多地采用。您會提高代碼的復雜性以達到10%的效率嗎?您應該知道,CPU速度每18個月將翻一番。因此,我對程序員的要求是,我不希望您的代碼先提高效率,并且我希望您的代碼能夠快速理解和維護80%的人。
總結:
在執行主函數之前,它主要初始化系統相關資源:
1。設置堆棧指針
2。初始化靜態和全局變量,即數據段的內容
3。分配非初始化部分的初始值:數字短,int,long等。為0linker是什么意思,bool是錯誤的,指針為null等,也就是.bss段的內容
4。運行全局構造函數,可能是C ++中類似的構造函數。
5。將主函數參數,argc,argv等傳遞給主函數,然后實際運行主函數
主要功能之前發生了什么
一些微妙的細節與本文的主題無關。我們不首先關注它。我們只需要知道啟動代碼是設置矢量表,然后跳到__ Main函數。跳到代碼段的特定部分如下:
[c-sharp]查看platercopy
reset_handler procexport reset_handler [弱]導入__ mainldr r0,= __ mainbx r0endp
當您看到__ -Main功能時,估計許多人認為這是主要功能或編譯名稱的別名,否則與MAIN相關的單詞將不再在啟動代碼中找到。但是事實是貝語網校,__ -Main和Main是完全不同的功能!如果這還不足以讓您感到驚訝,請讓我告訴您另一個事實:您找不到__框架代碼,因為這是由編譯器自動創建的!
如果您仍然對此持懷疑態度,則可以檢查MDK文檔,并找到一個描述:當鏈接看到Main()的定義時,它將自動創建。簡而言之,當編譯器發現主函數被定義時,它將自動創建__ -main。
我們基本上已經弄清楚了__ Main功能的起源,所以現在的問題是,這與Main有什么關系?實際上,__Main主要做兩件事:初始化C/C ++所需的資源并調用主函數。暫時不會討論初始化,但是“調用主函數”的功能可以幫助我們解決有關為什么稱為__ main的啟動代碼的疑問,但最后它可以轉向主函數。
如果初始化C/C ++所需的資源與特定情況分開,那么很難清楚地解釋。讓我們首先看一下編譯的裝配代碼段:
以__RT開頭的任何東西都用于初始化C/C ++運行時庫;從__ -scatterload開始時,根據離散文件的定義將代碼中的變量映射到相應的內存位置。在本文開頭回答問題的關鍵是__ -scatterload_copy函數!
讓我們在STM32F10X平臺上舉一個簡單的示例。首先,我們需要了解平臺的閃存地址從0x08000000開始,主要是存儲代碼。當SRAM以0x20000000開頭,也就是說,內存。然后C/C ++具有此代碼線:
[CPP]查看Platecopy
靜態int g_ival = 12;
當我們的程序開始運行時,我們通過IDE發現g_ival映射到內存地址0x20000000,并且該值是一個隨機數0xffffbe00,而不是代碼中的12個設置,如圖所示:
我們讓程序繼續執行。執行__ -scatterload_copy之后,我們發現g_ival已成為我們需要的初始值:
接下來是C/C ++庫的初始化,最后輸入了主函數,此時一切都準備就緒。
如果您僅限于桌面應用程序的開發,因為編譯的程序具有許多操作系統功能,它將給我們帶來極大的困惑linker是什么意思,以了解該程序的操作。只有進入嵌入式字段并在無需操作系統的支持的情況下,我們才能更好地了解軟件的運行方式。只有在這個時候,我們才能更清楚地知道,主要功能不是起點。
最后,如果您想學習C/C ++,則可以向編輯器“ 01”發送私人消息,以獲取材料,開發工具和聽力權限!