当从C程序的任何地方调用时,C程序中的RETURN和EXIT语句有什么区别?
- 返回是从函数调用返回的语言指令。
- exit是终止当前进程的系统调用(不是语言语句)。
当两者都做(几乎)相同的事情时,唯一的情况是在main()函数中,因为从main返回执行exit()。好的。
return示例:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <stdio.h>
void f (){
printf("Executing f
");
return;
}
int main (){
f ();
printf("Back from f
");
} |
如果执行此程序,它将打印:好的。
1 2
| Executing f
Back from f |
exit()的另一个例子:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include <stdio.h>
#include <stdlib.h>
void f (){
printf("Executing f
");
exit(0);
}
int main (){
f ();
printf("Back from f
");
} |
如果执行此程序,它将打印:好的。
你永远不会"从F回来"。还要注意调用库函数exit()所必需的#include 。好的。
另外请注意,exit()的参数是一个整数(它是启动程序进程可以获得的进程返回状态;常规用法是0表示成功或任何其他错误值)。好的。
返回语句的参数是函数的返回类型。如果函数返回void,则可以省略函数末尾的返回。好的。
最后一点,exit()有两种口味:_exit()和exit()。两种形式的区别在于,exit()和return from main在真正终止进程之前调用使用atexit()或on_exit()注册的函数,而_exit()(来自#include 或其同义词exit from #include 立即终止进程。好的。
现在也有一些特定于C++的问题。好的。
当C++退出函数时,C++比C执行更多的工作(EDOCX1,2,-ing)。具体来说,它调用超出范围的本地对象的析构函数。在大多数情况下,程序员在进程停止后不会太在意程序的状态,因此不会有太大的区别:分配的内存将被释放,文件资源将关闭等等。但如果析构函数执行ios,这可能会很重要。例如,自动创建的C++ EDCOX1(17)在调用退出时不会被刷新,可能会丢失一些未刷新的数据(另一方面,静态EDCOX1(17)将被刷新)。好的。
如果您使用的是好的C FILE*流,则不会发生这种情况。这些将在exit()上冲洗。实际上,规则与注册的exit函数相同,FILE*将在所有正常终端上刷新,包括exit(),但不调用_exit()或abort()。好的。
你还应该记住C++提供了一种摆脱函数的第三种方法:抛出异常。这种走出函数的方法将调用析构函数。如果在调用方链的任何位置都没有捕获到异常,则异常可以转到main()函数并终止进程。好的。
如果你从EDCOX1,1,或EDCOX1,2,或者在你的程序中的任何地方调用EDCOX1,0调用,就会调用静态C++对象的析构函数。如果程序使用_exit()或abort()终止,则不会调用它们。abort()在调试模式下最有用,目的是立即停止程序并获取堆栈跟踪(用于事后分析)。它通常隐藏在assert()宏后面,仅在调试模式下处于活动状态。好的。
exit()什么时候有用?好的。
exit()表示要立即停止当前进程。当我们遇到某种不可恢复的问题时,它可能对错误管理有一定的帮助,而这些问题将不再允许您的代码做任何有用的事情。当控制流很复杂并且错误代码必须一直向上传播时,这通常很方便。但请注意,这是一种糟糕的编码实践。在大多数情况下,静默结束进程更坏的行为和实际的错误管理应该是首选的(或者在C++中使用异常)。好的。
直接调用exit()如果在库中执行,则会特别糟糕,因为它将使库用户陷入困境,因此库用户应该选择是否执行某种错误恢复。如果你想要一个例子来说明为什么从图书馆调用exit()是不好的,它会导致人们问这个问题。好的。
有一个无可争议的合法使用exit()作为终止由fork()在支持它的操作系统上启动的子进程的方法。回到fork()之前的代码通常是一个坏主意。这是解释exec()系列函数为何永远不会返回调用方的基本原理。好的。好啊。
- exit()不是系统调用
- @安侬:你是对的,从技术上讲,这是一个回归系统的过程,但没有太大的区别。
- @Jonathanleffler在main()中更喜欢使用return或exit?查找此代码的示例。
- 我通常在main()中使用return。当然,我在main()的末尾使用return 0;,有时在函数体中使用exit();。我不喜欢关于EDCX1结尾的C99规则(0)相当于EDCOX1(5)结尾,这是一个愚蠢的特殊情况(尽管C++在伤害方面领先)。
- 注:C11标准具有附加功能:at_quick_exit()、_Exit()(也在C99中)、quick_exit()。_Exit()函数来自posix,但本质上与_Exit()相同。
- 如果返回执行exit,那么它们就不同了。结果将是相同的,但是如果您说它们做了相同的事情,然后说它们正在调用exit,那么它将解析为在main中调用exit,从而产生无穷的exit递归。
- @扎比斯:读得更好。我写的不是从主出口返回,而是从主出口调用的返回返回返回返回。换言之,从MAIN返回的调用就是退出程序。此外,函数调用今后既不返回也不退出,递归不能有任何可能的问题。我再说一遍:exit不是一个函数调用,它甚至不是一个典型的系统调用,因为如果它确实跳到了某个地方,但它永远不会从那里回来。
- 如果您想要一个例子来说明为什么在库中退出是不好的:它使人们问这个问题stackoverflow.com/q/34043652/168175。然后大概要么使用黑客,要么毫无理由地使用IPC。
- abort和exit的区别是:abort发送sigabrt信号,以便保留一个核心文件(如果ulimit-c允许的话)。因此,如果您希望在不调用静态析构函数的情况下使用core错误退出,那么可以使用abort。
- 是否可以避免或解决通过在main()函数中编写"两者都做(几乎)相同的…"而产生的神话?具体地说,在main()中使用这两种方法时,有什么区别或者没有区别?
- @Max:据我所知,主函数的返回是返回到主函数的调用方(内部函数不向程序员公开),它将执行退出程序所需的代码,而exit将跳转到该代码,无论它是从主函数调用还是从其他任何地方调用。这些差异取决于运行代码的生态系统(操作系统、编译器、libs等)。在某些情况下,可能根本就没有区别,而且无论如何,除非您在编写低级代码(即:如果您编写exit()实现,则它们很重要),否则所有这些都会发生在程序员的幕后。
- @克丽丝:回复是这样的。对main()的调用后面紧跟一个call/jump to exit()是合乎逻辑的,因为除此之外还需要做什么,exit()无论如何都应该这样做。现在我在其他的来源中读到,在C++的旧版本中,一些局部范围的析构函数没有被EXIT()调用,但是这被认为是Bug,并且差异不再存在。因此,如果没有操作系统或编译器错误,那么对exit(0)的调用应该完全等同于"返回0"-可能更快地执行2-3条机器指令,也可能被认为是"脏的"。
- @max:您还应该考虑程序入口点可能不是main()(实际上在Windows上不是,并且有一个gcc选项允许更改它)。从编译器的角度来看,main()是一个非常正常的函数,具有输入参数和返回值。它是MAIN的调用方,它知道在MAIN返回之后,它将退出程序。此外,不禁止递归调用main(甚至间接递归调用)。这些情况是非常罕见的,但是更改main()代码以执行与exit完全相同的操作将使它们不再具有附加值。
我写了两个程序:
和
1 2
| #include <stdlib.h>
int main (){exit(0)} |
执行gcc -S -O1后。这是我看到的装配时(仅重要零件):
1 2 3
| main:
movl $0, %eax /* setting return value */
ret /* return from main */ |
和
1 2 3 4 5
| main :
subq $ 8, %rsp /* reserving some space */
movl $ 0, %edi /* setting return value */
call exit /* calling exit function */
/* magic and machine specific wizardry after this call */ |
所以我的结论是:可以的时候用return,需要的时候用exit()。
- 除了结论外,这是一个非常好的答案;imho它激发了相反的结论:我们可以假定ret指令返回到可能需要做一些额外工作的点,但最终仍将调用exit()函数-或者如何避免执行exit()所做的任何操作?这意味着前者只做了一些额外的"重复"工作,而对第二个解决方案没有任何好处,因为在最后肯定会调用exit()。
- @max:不禁止从您自己的程序递归调用main。从此以后,您不应该假定从main返回将立即退出,这将破坏代码语义。在某些情况下,它甚至是有用的。例如,在将代码入口点更改为与main不同的内容之后,在调用main之前帮助准备/清除一些上下文。这甚至可以通过一些运行时代码注入方法来实现。当然,当它是你的程序,做任何你喜欢或相信是更容易阅读。
- @克里斯:这是一个很好的观点,之前没有提到过。虽然我认为递归调用main()是非常罕见的,但这种可能性比其他任何方法都能更好地澄清imho返回和退出(0)之间的区别。
在C语言中,在程序的启动函数(可以是main()、wmain()、_tmain()或编译器使用的默认名称)中使用时没有太大的差别。
如果您在main()中使用return,控制权将返回到c库中的_start()函数,该库最初启动您的程序,然后无论如何调用exit()。所以你用哪一个并不重要。
- 这很重要。exit()立即终止程序,无论在何处调用。仅返回退出当前函数。他们做相同事情的唯一位置是在main()中
- 谢谢,我已经修改了措辞。它不一定只存在于main()中,因为并非所有编译器都为启动函数使用相同的函数名。
- 我想你把所有的程序都写在一个大的主函数里?;-)
- 答案不完整,但仍有信息。
RETURN语句退出当前函数,EXIT()退出程序
1
| they are the same when used in main() function |
另外,RETURN是一个语句,而exit()是一个需要stdlb.h头文件的函数