必須從main開始程序執行,還是可以修改起始地址?程序執行是否始終從C中的main開始?
#include <stdio.h>
void fun();
#pragma startup fun
int main()
{
printf("in main");
return 0;
}
void fun()
{
printf("in fun");
}
該程序在in main
之前打印in fun
。
必須從main開始程序執行,還是可以修改起始地址?程序執行是否始終從C中的main開始?
#include <stdio.h>
void fun();
#pragma startup fun
int main()
{
printf("in main");
return 0;
}
void fun()
{
printf("in fun");
}
該程序在in main
之前打印in fun
。
在「的#pragma」命令在ANSI標準中指定,以具有任意實現定義的效果。在GNU C預處理器中,'#pragma'首先嚐試運行遊戲'流氓';如果失敗了,它會嘗試運行遊戲「黑客」;如果失敗了,它會嘗試運行顯示河內塔的GNU Emacs;如果失敗了,它會報告一個致命錯誤。無論如何,預處理不會繼續。
- 理查德M. Stallman的,GNU C預處理器,版本1.34
開始執行程序的啓動代碼,或 「運行」。這通常是一些名爲_start
的彙編程序,或者位於(在Unix機器上)位於編譯器軟件包附帶的文件crt0.o
中的某些彙編程序。它執行運行C可執行文件所需的設置(例如,爲C++設置stdin
,stdout
和stderr
,使用的向量爲atexit()
......它還包括初始化全局對象,即運行它們的構造函數)。只有這樣才能控制跳轉到main()
。
正如我在答案開頭的引用所表達的那樣雄辯,#pragma
所做的完全取決於您的編譯器。檢查它的文檔。 (我猜你的pragma startup
- 順便提一句#
- 告訴運行庫首先調用fun()
...)
其實我希望編譯器建設者有堅持斯托曼的立場。它可以讓我們從「一次性編譯指示」或源代碼硬禁用編譯器警告等愚蠢的東西中拯救我們...... – DevSolar
C程序不一定從main()
函數開始。有些代碼在main()
之前執行,它將所有未初始化的全局變量清零並用適當的值初始化其他全局變量。例如,考慮下面的代碼:
int a;
int b = 10;
int main()
{
int c = a * b;
return 0;
}
在該示例代碼以上,a
和b
被第一行中main()
執行之前分別分配0
和10
。
#pragma
指令用於定義實現定義的行爲。您的代碼#pragma
可能會在某些編譯器中編譯,但可能無法在另一個編譯器中編譯。
是不是由可執行加載程序完成的.data和.bss段的設置,而不是啓動代碼? – DevSolar
@devsolar:這可能並非總是如此。例如微控制器。我曾參與過OKI 411,OKI 431和PIC16F微型計算機。他們都有某種啓動/運行時代碼。順便說一句,我不知道這些如何編程爲個人電腦時典型地實現。我只聽說過'.data'和'.bss'這兩個名字,不太瞭解它們。你可以給我一些鏈接,我可以從中瞭解更多嗎? – Donotalo
基本的ELF對象文件佈局:Section .text包含機器代碼,.data包含初始化數據(在您的示例中爲'10')。 .bss是「零初始化」區域,當然不在可執行文件中,或者只是作爲「大小」數字;您將其留給加載程序以提供足夠的零初始化內存。當然,現實是更加困難的部分(包含調試信息或C++異常處理的部分或類似的東西)。查看維基百科,「數據段」。 – DevSolar
至於ISO C標準而言,入口點一個C程序總是main
(除非是一些實現定義的功能來覆蓋它)對東道主實現。對於「獨立實現」(通常是嵌入式系統,通常沒有操作系統),入口點是實現定義的。
可能的重複[你如何使用編譯啓動預處理器?](http://stackoverflow.com/questions/5617005/how-do-you-use-pragma-startup-preprocessor) – Mat