退出和回报的区别是什么?

当从 C 程序中的任何地方调用时,在 C 编程中返回语句和退出语句之间有什么区别?

127399 次浏览
  • Return 从当前函数返回; 它是一个语言关键字,如 forbreak
  • Exit () 终止整个程序,无论您从哪里调用它。

The only case when both do (nearly) the same thing is in the main() function, as a return from main performs an 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");
}

If you execute this program it prints:

Executing f

你永远不会得到“ Back from f”。还要注意调用库函数 exit()所必需的 #include <stdlib.h>

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

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

最后一点,exit()有两种口味: _exit()exit()。表单之间的区别在于,exit()(从 main 返回)在真正终止进程之前调用使用 atexit()on_exit()注册的函数,而 _exit()(从 #include <unistd.h>或从 #include <stdlib.h>的同义 _ Exit)立即终止进程。

Now there are also issues that are specific to C++.

C + + 在退出函数时(return-ing)比 C 执行更多的工作。具体来说,它调用超出范围的局部对象的析构函数。在大多数情况下,程序员不会太关心进程停止后程序的状态,因此它不会有太大的不同: 分配的内存将被释放,文件资源关闭等等。但是,如果析构函数执行 IOs,那么这可能很重要。例如,本地创建的自动 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()是不好的,它会导致实例人员询问 这个问题

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

In C, there's not much difference when used in the startup function of the program (which can be main(), wmain(), _tmain() or the default name used by your compiler).

如果你在 main()中使用 return,控制权就会回到最初启动程序的 C 库中的 _start()函数,然后它还是会调用 exit()。所以你用哪个真的不重要。

我写了两个程序:

int main(){return 0;}

还有

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

After executing gcc -S -O1. Here what I found watching 在装配时(只有重要部件) :

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

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

they are the same when used in main() function

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

在大多数情况下,使用 return和调用 exit()来终止 main()在 C 程序中是没有区别的。

如果您已经创建了依赖于 main()本地变量的 main()返回后将执行的代码,那么就会出现差异。其中一种表现形式就是 setvbuf():

int main(void)
{
char buffer[BUFSIZ];
setvbuf(stdout, buffer, _IOFBF, BUFSIZ);
…code using stdout…
return 0;
}

在本例中,当 main()返回时,通过 setvbuf()提供的缓冲区超出了作用域,但是刷新和关闭 stdout的代码将尝试使用该缓冲区。这会导致未定义的行为。

The other mechanism is to invoke atexit() with a function that accesses data from main() — via a pointer. This is harder to set up as the functions called via the atexit() mechanism are not given any arguments. So, you have to do something like this:

static void *at_exit_data = 0;


static void at_exit_handler(void)
{
char *str = at_exit_data;
printf("Exiting: %s\n", str);
}


int main(void);
{
char buffer[] = "Message to be printed via functions registered with at_exit()";
at_exit_data = buffer;
at_exit(at_exit_handler);
…processing…
return 0;
}

Again, the buffer pointed at by at_exit_data has ceased to exist when the program returned from main() and so the handler function invokes undefined behaviour.

还有一个相关的函数 at_quick_exit(),但是只有在调用 quick_exit()函数时才会调用它注册的函数,这就排除了在 main()返回之后调用函数的可能性。