退出和退货有什么区别?

sho*_*ona 86 c

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

kri*_*iss 138

  • return是从函数调用返回的语言的指令.
  • exit是终止当前进程的系统调用(不是语言语句).

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

示例return:

#include <stdio.h>

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

int main(){
    f();
    printf("Back from f\n");
}
Run Code Online (Sandbox Code Playgroud)

如果您执行此程序,它会打印:

Executing f
Back from f
Run Code Online (Sandbox Code Playgroud)

另一个例子exit():

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

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

int main(){
    f();
    printf("Back from f\n");
}
Run Code Online (Sandbox Code Playgroud)

如果您执行此程序,它会打印:

Executing f
Run Code Online (Sandbox Code Playgroud)

你永远不会得到"从f回来".还要注意#include <stdlib.h>调用库函数的必要性exit().

还要注意参数of exit()是一个整数(它是启动程序进程可以获得的进程的返回状态;传统的用法是0表示成功或任何其他错误值).

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

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

现在还存在特定于C++的问题.

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

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

您还应该记住,C++提供了第三种退出函数的方法:抛出异常.这种退出函数的方式调用析构函数.如果未在调用者链中的任何位置捕获,则异常可以转到main()函数并终止进程.

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

什么时候退出()有用吗?

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

exit()如果在库中完成,直接调用尤其糟糕,因为它会使库用户失败,应该是库用户选择是否实现某种错误恢复.如果你想要一个为什么exit()从库中调用是坏的一个例子,它会引导人们提出这个问题.

exit()作为支持它的操作系统上的fork()启动子进程的方法,有一种无可争议的合法用法.回到fork()之前的代码通常是个坏主意.这是解释为什么exec()系列的函数永远不会返回给调用者的基本原理.

  • exit()不是系统调用 (6认同)
  • 我通常在`main()`中使用`return`.当然,我在`main()`的末尾使用`return 0;` - 我有时在函数体中使用`exit();`.我不喜欢C99规则关于`main()`的结尾相当于`return 0;`的结尾; 这是一个愚蠢的特殊情况(虽然C++在破坏方面领先一步). (3认同)
  • 如果你想要一个例子来说明为什么退出库是不好的:它让人们问这个问题 http://stackoverflow.com/q/34043652/168175。然后大概要么无缘无故地使用 hack 或使用 IPC (3认同)
  • @Milan:一些IO被缓冲,这是OStream的cas。在这种情况下,刷新意味着数据实际上已发送到控制台/写入磁盘,而不仅仅是保存在缓冲区中。未刷新意味着数据仍在应用程序的某些内存缓冲区中,但尚未发送到系统。在 C++ 文档中,他们将数据发送到的底层系统对象称为“受控序列”。OStream 上有一个显式的刷新方法可以做到这一点。 (2认同)

小智 17

我写了两个程序:

int main(){return 0;}
Run Code Online (Sandbox Code Playgroud)

#include <stdlib.h>
int main(){exit(0)}
Run Code Online (Sandbox Code Playgroud)

执行后gcc -S -O1.这是我在装配时看到的(仅限重要部分):

main:
    movl    $0, %eax    /* setting return value */
    ret                 /* return from main */
Run Code Online (Sandbox Code Playgroud)

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 */
Run Code Online (Sandbox Code Playgroud)

所以我的结论是:尽可能使用return,exit()何时需要.

  • @Max:从您自己的程序中递归调用 main 是不被禁止的。从今以后你不应该假设从 main 返回会立即退出,这会破坏代码语义。在某些(罕见的)情况下,它甚至很有用。例如,在将代码入口点更改为与 main 不同的内容后,在调用 main 之前帮助准备/清除某些上下文。这甚至可以通过一些运行时代码注入方法来完成。当然,当它是你的程序时,你可以做任何你喜欢或相信更容易阅读的事情。 (2认同)

Dum*_*Guy 9

在C语言中,在程序的启动功能(可使用时有没有太大的区别main(),wmain(),_tmain()或你的编译器使用的默认名称).

如果您return进入main(),控制权将返回到_start()最初启动您的程序的C库中的函数,然后exit()无论如何都会调用该函数.所以你使用哪一个并不重要.

  • 我想你在一个大的主要功能中编写所有程序?;-) (7认同)
  • 这非常重要。无论在何处调用,exit() 都会立即终止程序。return 只退出当前函数。他们做同样事情的唯一位置是在 main() (3认同)