搞定技术面试-在 main函数之前发生了什么

4,011 阅读2分钟

在 main函数之前发生了什么

对于编程人员来讲,main 函数是程序的入口,但事实上 main 函数之前也发生了很多操作。在 main 函数开始前,分成两部分 “系统调用部分” 和 “C++ 程序自身的部分”。

我们首先假设程序的 main 函数原型是int main(int argc, char *argv[]);,其中,argc 指命令行参数的数目, argv 是指向参数的各个指针所构成的数组。

系统调用部分

对于 Linux 系统而言,当内核执行 C 程序时使用 exec 函数,在调用 main 前先调用一个特殊的启动例程。可执行文件将此启动例程指定为程序的起始地址。启动例程从内核取得命令行参数和环境变量值。

  1. 简而言之,系统会为你设置栈,并且将argc,argvenvp压入栈中。文件描述符0,1和2(stdin, stdout和stderr)保留shell之前的设置。
  2. 加载器会帮你完成重定位,调用你设置的预初始化函数。
  3. 当所有搞定之后,控制权会传递给_start(),即程序的入口函数

程序本身的 main() 执行前

  1. 入口函数对运行库和程序运行环镜进行初始化,包括 堆、I/O、线程、全局变量构造等等。
  2. 入口函数完成初始化后,调用 main 函数,正式开始执行程序主体部分。

main() 结束之后呢?

  1. main函数执行完毕后,返回到入口函数,入口函数进行清理工作,包括全局变量的析构、堆销毁、关闭I/O等,然后系统调用结束进程。
  • main函数结束可以通过 return 0;或者 exit(0) 来结束,此时程序并非直接结束,而是先调用一些终止处理程序然后再结束。可以使用int atexit(void (*func)(void));来追加自定义终止处理程序,终止处理程序由 exit函数自动调用,调用顺序与登记顺序相反。
  • 如果main函数发生了异常或者使用_exit_Exit来退出程序,则不会调用终止处理程序。

Reference

  1. APUE 3.rd Sec.7
  2. 程序员的自我修养