之前思考过一个问题:为什么C语言要有main函数,而且程序从main函数开始执行,查了一下资料,以下是我整理的一些内容。
C语言为什么要有main函数
之前写时 shell
脚本,发现 shell
直接将源程序写在源文件中,然后就从头至尾就开始执行了,并没有像 C语言那样需要一个 main 函数,然后程序从 main 函数开始执行。实际上大多数的脚本语言都是这样——并不需要注明程序执行的开始位置。
我们知道 C程序从编写到执行要经过:预处理——编译——链接 几个阶段,每个编辑单元(.c 文件)都是独立生成自己的目标文件(.o 文件),最后由链接器将这些目标文件链接到一起,生成可执行文件,在该期间,可能还会链接一些库文件。
对于多个编辑单元,链接器需要知道程序的入口在哪里,于是就利用函数不能重复定义的机制,规定程序的入口函数为 main
函数,如果一个程序中超过一个入口函数,编译器就会报错。
没有main函数行不行
事实上,C语言程序不一定非得有main函数。
C语言标准在一开始(C90标准 5.1.2条),就规定了程序的执行环境。
对于没有操作系统的环境来说,C程序的入口函数是什么都可以(也就是说的在单片机的C程序里,或者在操作系统的底层代码的C入口处,不需要是main函数)。对于有操作系统的环境来说,C程序的入口是main函数。而且被声明为以下两者其中之一:
int main(void);
int main(int argc, char * argv[]);
谁调了main函数
我们先看看如果C程序没有买呢函数会怎样:
#include <stdio.h>
int nomain()
{
printf("Hello World.\n");
return 0;
}
结果如下:
没有main函数时,程序编译的结果是:在函数 _start 中使用了未定义的 main 函数,这说什么?说明是 start
函数调用了 main
函数,实际上 start
函数是操作系统开始执行C程序的起点。
我们再来看个例子确认一下:
参数 nostdlib
表示不使用标准库,我们加上该参数编译时,编译器告诉我们,找不到符号 _start
,这也就说明了 _start
函数是操作系统执行C程序的起点。
main函数被调之前和之后
我们写的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】