沒有main函數,,
我們常用gcc main.c -o main
命令編譯一個程序,
其實也可以分三步做,第一步生成匯編代碼,第二步生成目標文件,第三步生成可執行文件:
$ gcc -S main.c (注意S是大寫的)
$ gcc -c main.s
$ gcc main.o
在main.c中這么寫到:
#include<stdio.h>
int m(){
printf("this is a test!");
return 0;
}
很明顯,這個程序不能運行,因為沒有main函數,試一下
gcc main.c -o main
報錯:
[ming@localhost codetest]$ gcc main.c -o main
/usr/lib/gcc/i686-redhat-linux/4.5.1/../../../crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: ld 返回 1
整個程序的入口點是
crt1.o
中提供的
_start
,它首先做一些初始化工作(以下稱為啟動例程,Startup Routine),然后調用C代碼中提供的
main
函數。所以,以前我們說
main
函數是程序的入口點其實不准確,
_start
才是真正的入口點,而
main
函數是被
_start
調用的。在_start中指名了要掉main,而程序中只有m函數,所以就運行不起來。
C程序的鏈接過程:

可以看到,,在生成main的可執行程序的時候,,其實還加入了其他的一些東西一起鏈接在一起執行的
main
函數最標准的原型應該是int main(int argc, char *argv[])
,也就是說啟動例程會傳兩個參數給main
函數,這兩個參數的含義我們學了指針以后再解釋。我們到目前為止都把main
函數的原型寫成int main(void)
,這也是C標准允許的,如果你認真分析了上一節的習題,你就應該知道,多傳了參數而不用是沒有問題的,少傳了參數卻用了則會出問題。
由於main
函數是被啟動例程調用的,所以從main
函數return
時仍返回到啟動例程中,main
函數的返回值被啟動例程得到,如果將啟動例程表示成等價的C代碼(實際上啟動例程一般是直接用匯編寫的),則它調用main
函數的形式是:
exit(main(argc, argv));
也就是說,啟動例程得到main
函數的返回值后,會立刻用它做參數調用exit
函數。exit
也是libc
中的函數,它首先做一些清理工作,然后調用上一章講過的_exit
系統調用終止進程,main
函數的返回值最終被傳給_exit
系統調用,成為進程的退出狀態。我們也可以在main
函數中直接調用exit
函數終止進程而不返回到啟動例程,例如:
#include <stdlib.h> int main(void) { exit(4); }
這樣和int main(void) { return 4; }
的效果是一樣的。在Shell中運行這個程序並查看它的退出狀態:
$ ./a.out
$ echo $?
4
按照慣例,退出狀態為0表示程序執行成功,退出狀態非0表示出錯。注意,退出狀態只有8位,而且被Shell解釋成無符號數,如果將上面的代碼改為exit(-1);
或return -1;
,則運行結果為
$ ./a.out
$ echo $?
255