没有main函数,, 我们常用gcc main.c -o main命令编译一个程序, 其实也可以分三步做,第一步生成汇编代码,第二步生成目标文件,第三步生成可执行文件: $ gcc -S main.c (注意S是大写的) $ gcc -c main.s $ gcc main.o 在main.c中这么写到: #include 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 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 (责任编辑:IT) |