沒有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
