之前思考过一个问题:为什么C语言要有main函数,而且程序从main函数开始执行,查了一下资料,以下是我整理的一些内容。
之前写时 shell 脚本,发现 shell 直接将源程序写在源文件中,然后就从头至尾就开始执行了,并没有像 C语言那样需要一个 main 函数,然后程序从 main 函数开始执行。实际上大多数的脚本语言都是这样——并不需要注明程序执行的开始位置。
我们知道 C程序从编写到执行要经过:预处理——编译——链接 几个阶段,每个编辑单元(.c 文件)都是独立生成自己的目标文件(.o 文件),最后由链接器将这些目标文件链接到一起,生成可执行文件,在该期间,可能还会链接一些库文件。
对于多个编辑单元,链接器需要知道程序的入口在哪里,于是就利用函数不能重复定义的机制,规定程序的入口函数为 main 函数,如果一个程序中超过一个入口函数,编译器就会报错。
事实上,C语言程序不一定非得有main函数。 C语言标准在一开始(C90标准 5.1.2条),就规定了程序的执行环境。 对于没有操作系统的环境来说,C程序的入口函数是什么都可以(也就是说的在单片机的C程序里,或者在操作系统的底层代码的C入口处,不需要是main函数)。对于有操作系统的环境来说,C程序的入口是main函数。而且被声明为以下两者其中之一:
int main(void); int main(int argc, char * argv[]);我们先看看如果C程序没有买呢函数会怎样:
#include <stdio.h> int nomain() { printf("Hello World.\n"); return 0; }结果如下:
没有main函数时,程序编译的结果是:在函数 _start 中使用了未定义的 main 函数,这说什么?说明是 start 函数调用了 main 函数,实际上 start 函数是操作系统开始执行C程序的起点。 我们再来看个例子确认一下:
参数 nostdlib 表示不使用标准库,我们加上该参数编译时,编译器告诉我们,找不到符号 _start,这也就说明了 _start 函数是操作系统执行C程序的起点。
我们写的C程序一开始就可以使用:stdin、stdout、stderr,这些标准流是什么时候打开的呢,main函数的栈帧空间是谁初始化的呢? 通常,我们会在编译器的环境中找到一个名字类似于 crt0.o 的文件,这个文件中包含了我们刚才所说的 __start 符号。(crt 大概是 C Runtime 的缩写),crt0里面都干了些什么呢?如下:
//伪代码 section .text: __start: : init stack;// 初始化栈 init heap;//初始化堆 open stdin;//打开标准输入 标准输出、标准错误三个流 open stdout; open stderr; : push argv;//传递main函数的参数 push argc; call _main; //调用 main : return 0 ;//从main函数返回 destory heap;//清理工作 close stdin; close stdout; close stderr; : call __exit;参考内容 - https://www.zhihu.com/question/28360770 - http://blog.sina.com.cn/s/blog_4b34c6790100lqvc.html
【作者:果冻 http://blog.csdn.net/jelly_9】
