c并非所有的代码路径都返回值_深度理解:main函数的返回值

最近碰到这样的一个问题:main函数的返回值的作用。

main函数的前世今生

每一个C程序都会有一个main函数作为入口点,这里所谓的入口点,也即程序一开始就会尝试找到main函数的位置,并从main函数的第一行代码开始执行。

那么,第一个问题:入口点之前是什么?main函数执行完之后,又是什么?这有点像:宇宙大爆炸之前的那一刻是什么状态?

我们来创建一个最简单的C程序,来看看入口点之前是什么?

如下图所示,我使用VS2010创建了一个控制台应用程序。

cd7a5b71e346a3fe9e89e2abda723bc5.png

代码十分简单,我们在main函数中打印了一句hello,然后返回了0。

接下来,我们在printf函数处设置一个断点,然后F5启动调试。程序如期的在printf处中断了下来,我们先来看看调用堆栈。

0bc6c28840ca422796894dfda7a939bd.png

在调用堆栈中,我们看到在main函数调用之前,有两次CRT库函数调用,具体代码如下:

406ab0e0eccc0cfbc982600531d5f982.png
1d760983d23f936aa2abe4817e4909ad.png
2cfa1cc888053e51ae89a49d78d8e7b1.png

从以上观察得出结论:系统CRT的库中的wmainCRTStartup/mainCRTStartup为实际用户程序的入口点,我们自己编写的main函数由CRT调用,并且,在调用之前CRT会尝试对一些底层基础设施进行初始化,包括默认的异常处理函数表,各种底层中断的处理策略等。这些基础性的工作完成之后,CRT调用我们的main函数进入应用程序的实际代码中。

好了,看了大爆炸之前的那一刻,我们来研究一下main函数执行完毕后,会发生什么?

还是继续进行单步调试,看看main函数返回后,代码如何走:

e22b6119e2258fe4a9a06054efba6e21.png
6b58b55bb196c63645c324d165ce7f57.png
7c10517b1b1e94dba7191372d353a224.png
379c2fe914946fd27b5013a9b56522bf.png
1793f869c42f77b36c34956163c86014.png

跟踪到最后,我们发现,CRT在收到main函数返回值后,将这个值传递了Win32API ExitProcess,当程序执行这个API时,操作系统将终止应用程序并释放整个进程资源,我们在main函数中准备的返回值,传递给了操作系统,操作系统会记录这个准备死亡的进程及其返回值,然后,进程死亡。

main返回值到底有什么用?

我们打开命令行窗口,分别让main返回0和77这两个不一样的值,然后使用%ERRORLEVEL%打印程序的退出代码,如下图:

7f7abe1e68018bef8f1aa3278b090f77.png

我们可以看到,main函数的返回值,被用作了程序的退出代码。如果您在Linux下做测试,可以使用echo %?来打印应用程序的退出代码。

结论

1) main函数,从函数调用链来看,仅仅是又一个非常普通的C函数,但同时也不普通,它唯一的代表了应用程序的入口点。

2) main函数的返回值将被操作系统用作进程的退出代码,利用这个特性,我们可以使用返回值来标识某项任务是否成功执行,例如,如果任务成功执行,则返回0,否则,返回与具体错误相关的整数,我的习惯是:使用大于0的整数来标识各种可能发生的错误,因为,一旦涉及到负数(有符号),水就比较深了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值