入口函数和程序初始化

入口函数和程序初始化

程序从main开始吗?

正如基督徒认为世界的诞生起于7天创世一样,任何一个合格的C/C++程序员都应该知道一个事实:程序从main函数开始。但是事情的真相真是如此吗?如果你善于观察,就会发现当程序执行到main函数的第一行时,很多事情都已经完成了:

【铁证1】下面是一段C语言代码:

#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);

}

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

【铁证2】而在C++里,main之前能够执行的代码还会更多,例如如下代码:

#include <string>

using namespace std;

string v;

double foo()

{

    return 1.0;

}

double g = foo();

int main(){}

在这里,对象v的构造函数,以及用于初始化全局变量g的函数foo都会在main之前调用。

【铁证3atexit也是一个特殊的函数。atexit接受一个函数指针作为参数,并保证在程序正常退出(指从main里返回或调用exit函数)时,这个函数指针指向的函数会被调用。例如:

void foo(void)

{

    printf(“bye!/n”);

}

int main()

{

    atexit(&foo);

    printf(“endof main/n”);

}

atexit函数注册的函数的调用时机是在main结束之后,因此这段代码的输出是:

endof main

bye!

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

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

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

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值