入口函数和程序初始化

可以参考《程序员的自我修养》装载、链接和库

linux加载程序的过程简单点说就是linux建立一个进程,然后读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系,最后把cpu的指令寄存器设置成可执行文件的入口地址,启动执行。然后依次执行代码段的指令。

 

 

1、程序并不是从main函数开始的。比如下面的程序:

#include <stdio.h>
#include <stdlib.h>

int a = 3;

int main(int argc, char *argv[])
{
	int *p = (int *)malloc(sizeof(int));
	scanf("%d", p);
	printf("%d", a + *p);
	free(p);
}


#include <string>
using namespace std;
string v;
double foo()
{
	return 1.0;
}

double g = foo();
int main() {}

  

从代码中我们可以看到,在程序刚刚执行到main的时候,全局变量的初始化过程已经结束了(a的值已经确定),main函数的两个参数(argc和argv)也被正确传了进来。此外,在你不知道的时候,堆和栈的初始化悄悄地完成了,一些系统I/O也被初始化了,因此可以放心地使用printf和malloc。

第二个C++程序,对象v的构造函数,以及用于初始化全局变量g的函数foo都会在main之前调用。

 

操作系统装载程序之后,首先运行的代码并不是main的第一行,而是某些别的代码,这些代码负责准备好main函数执行所需要的环境,并且负责调用main函数,这时候你才可以在main函数里放心大胆地写各种代码:申请内存、使用系统调用、触发异常、访问I/O。在main返回之后,它会记录main函数的返回值,调用atexit注册的函数,然后结束进程。

运行这些代码的函数成为入口函数或入口点,视平台的不同而有不同的名字。程序的入口点实际上是一个程序的初始化和结束部分,它往往是运行库的一部分。一个典型的程序运行步骤大致如下:

(1)操作系统在创建进程后,把控制权交到了程序的入口,这个入口往往是运行库中的某个入口函数。

(2)入口函数对运行库和程序运行环境进行初始化,包括堆、I/O、线程、全局变量构造,等等

(3)入口函数在完成初始化之后,调用main函数,正式开始执行程序主题部分。

(4)main函数执行完毕以后,返回到入口函数,入口函数进行清理工作,包括全局变量析构、堆销毁、关闭I/O等,然后进行系统调用结束进程。

 

posted on 2019-06-05 16:31  EMH1899  阅读(372)  评论(0编辑  收藏  举报

导航