从C中的主函数返回与退出[重复]

Posted

技术标签:

【中文标题】从C中的主函数返回与退出[重复]【英文标题】:Return vs Exit from main function in C [duplicate] 【发布时间】:2020-11-28 06:05:16 【问题描述】:

您好,我想知道从 main 函数返回和退出的区别是什么。当它们中的每一个被调用时,幕后会发生什么,以及在每种情况下如何返回控件。 如果有人能深入研究这个主题,我会非常感激。

【问题讨论】:

exit() 的重点在于,您可以从嵌套函数中调用它,而不仅仅是从 main。在功能上它们是等价的。 当您调用 exit 或返回调用 main 的 CRT 启动代码时,C 库执行的详细信息显然取决于操作系统和 C 库。 (一般来说,它当然必须实现所有 ISO C 要求,例如刷新 stdio 缓冲区和运行 atexit 函数)。我认为通常main 的调用者会做与exit(main(argc, argv)) 等效的事情,所以无论哪种方式都会发生同样的事情。如果您正在某个特定平台上寻找 asm 详细信息,请在您的问题中说出哪一个。 (或 main 之外的单步 asm 指令)。 这能回答你的问题吗? What is the difference between exit and return? 作为理解 CRT 启动代码的一部分,对于 GNU/Linux,请参阅 Linux x86 Program Start Up or - How the heck do we get to main()?。它提到__libc_start_main 使用main 的返回值调用exit。由于这个问题并非特定于任何一组 C 实现,但我不能真正将其发布为答案。你不会得到比 rici 关于实现通常如何做的答案更具体的答案。 【参考方案1】:

没有区别。

在幕后发生的事情(至少在一些流行的操作系统上)是这样的:

// Set up argc and argv
int retcode = main(argc, argv);
exit(retcode);

C 标准保证了这种行为:

...从对main 函数的初始调用返回等效于以main 函数返回的值作为其参数调用exit 函数...(§5.1.2.2.3 )

【讨论】:

值得注意的是,如果 C99 实现以这种方式处理程序,则需要在名为 main() 的函数末尾添加一个 return 0;,除非这样的语句是无法访问。 @supercat:这种情况在我引用的标准的同一段落中进行了介绍。但是,当然。 我真的想在这里避免TMI syndrome,但正如@acorn 所说,有一个区别:如果你返回,那么自动对象的生命周期就会结束。如果您使用atexit() 导致某些函数在退出时触发并且该函数引用一个包含指向某个自动对象的指针的静态变量,那将有所不同。 “不要那样做”似乎不值得警告。你可以看到这个效果:给这个example code添加一个额外的运行时参数。 在其 CRT + libc 中执行此操作的实现细节的一个示例:参见 Linux x86 Program Start Up or - How the heck do we get to main()? - __libc_start_main 获取一个指向 main 的函数指针,它使用它然后调用 @987654332 @ 带有返回值。 @PeterCordes:那是我所指的流行操作系统之一 :-)【参考方案2】:

基本没有区别。但是,exit() 很有用,因为它允许您从不同于main() 的其他功能中退出程序。

唯一形式上的区别是:

...在 main 中声明的具有自动存储持续时间的对象的生命周期将结束...

main返回的情况。


如果您需要更多详细信息,我建议您阅读最新的 C 标准,特别是第 5.1.2.2.3 节:

...从对main 函数的初始调用返回等效于以main 函数返回的值作为参数调用exit 函数...

以及第 7.22.4.4 节:

exit 函数导致正常的程序终止发生...

请注意,还有其他方法可以退出程序,例如 abortquick_exit_Exit

【讨论】:

【参考方案3】:

除了其他答案说这两种方法几乎相同:

从汇编程序员的角度来看,使用exit() 的主要区别在于我们不必(保存或)恢复被调用者保存寄存器或返回地址(如果 ABI 将其放入注册,即)。

如果 main 返回其调用者,那么 main 应该遵守 ABI 的寄存器保存要求。

【讨论】:

【参考方案4】:

C 2018 5.1.2.2.3 1 告诉我们在托管环境中会发生什么:

如果main函数的返回类型是与int兼容的类型,则从初始调用main函数返回相当于用@返回的值调用exit函数987654325@ 函数作为其参数;到达终止main函数的返回值0。如果返回类型与int不兼容,则返回宿主环境的终止状态未指定。

因此,在托管环境中,您可能认为是“正常”C 环境,return x; 从初始调用 main 等效于 exit(x);,如果它声明为具有兼容的返回类型与int。 (C 实现可以定义其他允许的声明。)

在独立环境中,5.1.2.1 2 告诉我们:

独立环境中程序终止的效果是由实现定义的。

exit 的行为在 7.22.4.4 中指定:

3 首先,所有由atexit 函数注册的函数都被调用,按照它们注册的相反顺序调用,除了在注册时已经调用的任何先前注册的函数之后调用一个函数……

4 接下来,刷新所有打开的带有未写入缓冲数据的流,关闭所有打开的流,并删除所有由tmpfile 函数创建的文件。

5 最后,控制权返回到宿主环境。如果status [exit 的参数] 的值为零或EXIT_SUCCESS,则返回状态成功终止的实现定义形式。如果status 的值为EXIT_FAILURE,则返回状态不成功终止 的实现定义形式。否则返回的状态是实现定义的。

【讨论】:

以上是关于从C中的主函数返回与退出[重复]的主要内容,如果未能解决你的问题,请参考以下文章

C语言中的main()函数返回值是啥?

C语言的主函数最多有允许有几个形式参数?

将整数参数传递给 C 中的主函数

C返回长度大于3的垃圾值[重复]

C语言中运行中,main函数被重复定义,后面的就不能运行了怎么办,下午考试,求高手

C语言中总是从main函数开始执行,那执行好main函数后,是按照从上到下的顺序执行吗