退出和返回有啥区别? [复制]

Posted

技术标签:

【中文标题】退出和返回有啥区别? [复制]【英文标题】:What is the difference between exit and return? [duplicate]退出和返回有什么区别? [复制] 【发布时间】:2011-03-28 16:08:38 【问题描述】:

从 C 程序中的任何位置调用时,C 编程中的 return 和 exit 语句有什么区别?

【问题讨论】:

【参考方案1】: return 从当前函数返回;它是一个语言关键字,例如 forbreakexit() 终止整个程序,无论您从哪里调用它。 (在刷新 stdio 缓冲区等之后)。

两者(几乎)做同样事情的唯一情况是在 main() 函数中,因为 main 的返回执行 exit()

在大多数 C 实现中,main 是一个真正的函数,由一些启动代码调用,执行类似于 int ret = main(argc, argv); exit(ret); 的操作。 C 标准保证如果 main 返回时会发生与此等效的事情,但是实现会处理它。

return 为例:

#include <stdio.h>

void f()
    printf("Executing f\n");
    return;


int main()
    f();
    printf("Back from f\n");

如果你执行这个程序,它会打印:

Executing f
Back from f

exit() 的另一个例子:

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

void f()
    printf("Executing f\n");
    exit(0);


int main()
    f();
    printf("Back from f\n");

如果你执行这个程序,它会打印:

Executing f

你永远不会得到“从 f 回来”。还要注意调用库函数exit() 所必需的#include &lt;stdlib.h&gt;

还要注意exit()的参数是一个整数(它是launcher进程可以获得的进程的返回状态,常规用法是0表示成功,其他任何值表示错误)。

return 语句的参数是函数的返回类型。如果函数返回void,可以省略函数末尾的return。

最后一点,exit() 有两种口味 _exit()exit()。形式之间的区别在于exit()(并从main 返回)在真正终止进程之前调用使用atexit()on_exit() 注册的函数,而_exit()(来自#include &lt;unistd.h&gt;,或其同义词_Exit from #include &lt;stdlib.h&gt; ) 立即终止进程。

现在还有一些 C++ 特有的问题。

在退出函数时,C++ 比 C 执行更多的工作 (return-ing)。具体来说,它调用超出范围的本地对象的析构函数。在大多数情况下,程序员不会在乎进程停止后程序的状态,因此不会有太大的区别:分配的内存将被释放,文件资源关闭等等。但是你的析构函数是否执行 IO 可能很重要。例如,在调用 exit 时不会刷新本地创建的自动 C++ OStream,并且您可能会丢失一些未刷新的数据(另一方面,静态 OStream 将被刷新)。

如果您使用旧的 C FILE* 流,则不会发生这种情况。这些将在exit() 上刷新。实际上,规则与注册退出函数的规则相同,FILE* 将在所有正常终止时刷新,包括exit(),但不会调用_exit() 或 abort()。

您还应该记住,C++ 提供了第三种退出函数的方法:抛出异常。这种退出函数的方式调用析构函数。如果在调用者链中的任何地方都没有捕获到它,则异常可以向上传递到 main() 函数并终止进程。

如果您在程序中的任何位置从main()exit() 调用return,则将调用静态C++ 对象(全局)的析构函数。如果程序使用_exit()abort() 终止,则不会调用它们。 abort() 在调试模式下最有用,目的是立即停止程序并获取堆栈跟踪(用于事后分析)。它通常隐藏在 assert() 宏后面,仅在调试模式下有效。

exit() 什么时候有用?

exit() 表示您想立即停止当前进程。当我们遇到某种无法恢复的问题时,它可能对错误管理有一些用处,这些问题不允许您的代码再做任何有用的事情。当控制流很复杂并且错误代码必须一直向上传播时,它通常很方便。但请注意,这是不好的编码习惯。在大多数情况下,静默结束进程是更糟糕的行为,应该首选实际的错误管理(或者在 C++ 中使用异常)。

如果在库中直接调用exit() 尤其糟糕,因为它会使库用户陷入困境,并且应该由库用户选择是否实施某种错误恢复。如果你想举例说明为什么从库中调用 exit() 不好,它会导致例如人们询问 this question。

在支持它的操作系统上,exit() 作为结束由 fork() 启动的子进程的方式是无可争议的合法使用。回到 fork() 之前的代码通常是个坏主意。这就是解释为什么 exec() 系列的函数永远不会返回给调用者的理由。

【讨论】:

exit() 不是系统调用 我通常在main()中使用return。当然,我在main() 的末尾使用return 0; — 我有时在函数体中使用exit();。我不喜欢 C99 规则关于从 main() 的末尾脱落等于 return 0; 的末尾;这是一个愚蠢的特殊情况(尽管 C++ 率先造成损害)。 注意:C11 标准具有附加功能at_quick_exit()_Exit()(也在C99 中)和quick_exit()_exit() 函数来自 POSIX,但本质上与 _Exit() 相同。 如果你想要一个例子来说明为什么退出图书馆是不好的:它会让人们问这个问题***.com/q/34043652/168175。然后大概要么使用 hack 要么无缘无故地使用 IPC @Milan:一些 IO 被缓冲,这是 OStream 的 cas。在这种情况下,flushed 意味着数据实际上已发送到控制台/写入磁盘,而不仅仅是保存在缓冲区中。未刷新意味着数据仍在应用程序的某些内存缓冲区中,但尚未发送到系统。在 C++ 文档中,他们将数据发送到的底层系统对象称为“受控序列”。 OStream 上有一个明确的刷新方法可以做到这一点。【参考方案2】:

return语句退出当前函数,exit()退出程序

they are the same when used in main() function

return 也是一个语句,而 exit() 是一个需要 stdlb.h 头文件的函数

【讨论】:

它们是相同的 if main 被任何 in 程序中的任何函数调用。这很少见;大多数程序不使用递归或可重入 main,但如果我们谈论的是语言细节,那么这是可能的。【参考方案3】:

我写了两个程序:

int main()return 0;

#include <stdlib.h>
int main()exit(0)

执行gcc -S -O1后。这是我发现的 组装时(仅重要部件):

main:
    movl    $0, %eax    /* setting return value */
    ret                 /* return from main */

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()

【讨论】:

这是一个很好的答案,除了结论;恕我直言,它激发了相反的动机:我们可以假设 ret 指令返回到可能完成一些额外工作的点,但最后无论如何都会调用 exit() 函数 - 或者如何避免做什么 exit() 做什么?这意味着前者只是做了一些额外的“重复”工作,对第二种解决方案没有任何好处,因为无论如何在最后肯定会调用 exit()。 @Max: 从你自己的程序中递归调用 main 是不被禁止的。从此以后,您不应假设从 main 返回会立即退出,这会破坏代码语义。在某些(罕见)情况下,它甚至很有用。例如,在将代码入口点更改为与 main 不同的东西之后,在调用 main 之前帮助准备/清除一些上下文。这甚至可以通过一些运行时代码注入方法来完成。当然,当它是你的程序时,你可以做任何你喜欢或认为更容易阅读的事情。 @kriss:这是一个很好的观点,之前没有提到。虽然我认为 main() 被递归调用是非常罕见的,但这种可能性比其他任何事情都更清楚地说明了 return 和 exit(0) 之间的区别。【参考方案4】:

在C语言中,用于程序的启动函数(可以是main()wmain()_tmain()或者你的编译器使用的默认名称)没有太大区别。

如果您在main() 中使用return,则控制权会返回到最初启动您的程序的C 库中的_start() 函数,然后无论如何都会调用exit()。因此,您使用哪一个并不重要。

【讨论】:

这很重要。 exit() 立即终止程序,无论它在哪里被调用。 return 只退出当前函数。他们做同样事情的唯一位置是在 main() 谢谢,我已经修正了措辞。它不一定只在 main() 中,因为并非所有编译器都对启动函数使用相同的函数名。 我猜你把所有的程序都写在一个大的 main 函数中? ;-) 答案不完整,但仍然提供信息。

以上是关于退出和返回有啥区别? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

死信队列和退出队列有啥区别?

“停止”和“退出”容器有啥区别?

C语言中exit(0)与exit(1)有啥区别??

在文件和终端中运行退出命令有啥区别

请问C++中如果需要中途退出程序,exit(1)和exit(0)以及return有啥区别呢? 谢谢!

React Transition Group:出现、进入、退出事件和进入、活动完成类名后缀有啥区别?