C中的return n和exit(n)有什么区别?


9

是否有任何区别return n(在main功能),并exit(n)用C?它是由C或POSIX标准定义的,还是取决于OS或编译器?

Answers:


5

在大多数情况下,没有什么区别,但这是一个C程序,根据它使用return 0;还是,其行为可能会有所不同exit(0);

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

static char *message;

void cleanup(void) {
    printf("message = \"%s\"\n", message);
}

int main(void) {
    char local_message[] = "hello, world";
    message = local_message;
    atexit(cleanup);
#ifdef USE_EXIT
    puts("exit(0);");
    exit(0);
#else
    puts("return 0;");
    return 0;
#endif
}

由于atexit()调用,或者exit(0);return 0;导致cleanup函数被调用。不同之处在于,如果程序调用exit(0);,则在对“调用” main()仍处于活动状态时进行清除,因此该local_message对象仍然存在。执行return 0;,但是,立即终止的调用main()调用cleanup()函数。由于cleanup()引用(通过全局message指针)指向本地分配给的对象main,并且该对象不再存在,因此行为未定义。

这是我在系统上看到的行为:

$ gcc -DUSE_EXIT c.c -o c && ./c
exit(0);
message = "hello, world"
$ gcc c.c -o c && ./c
return 0;
message = ""
$ 

不运行程序就-DUSE_EXIT无法做任何事情,包括崩溃或打印"hello, world"(如果所使用的内存local_message碰巧没有被破坏)。

但是,实际上,只有在内部局部定义的对象通过保存指向它们的指针而main()在外部可见时,这种差异才会显示main()出来。这可能发生在argv。(我系统上的实验表明,argv和所指向的对象*argv在从返回后仍然存在main(),但是您不应该依赖于此。)


16
  • 对于C
    标准说,从初始调用到main的返回等同于调用exit。但是,如果在清理过程中可能需要main本地数据,则不能期望从main返回数据。

  • 对于C ++

当使用exit(0)退出程序时,不会调用本地范围内的非静态对象的析构函数。但是,如果使用return 0,则将调用析构函数。

程序1 –-使用exit(0)退出

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

using namespace std;

class Test {
public:
  Test() {
    printf("Inside Test's Constructor\n");
  }

  ~Test(){
    printf("Inside Test's Destructor");
    getchar();
  }
};

int main() {
  Test t1;

  // using exit(0) to exit from main
  exit(0);
}

输出:内部测试的构造函数

程序2 –使用return 0退出

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

using namespace std;

class Test {
public:
  Test() {
    printf("Inside Test's Constructor\n");
  }

  ~Test(){
    printf("Inside Test's Destructor");
  }
};

int main() {
  Test t1;

   // using return 0 to exit from main
  return 0;
}

输出:内部测试的构造函数
内部测试的构造函数

例如,如果析构函数具有释放资源(如关闭文件)的代码,则调用析构函数有时很重要。

请注意,即使我们调用exit(),静态对象也将被清除。例如,请参见以下程序。

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

using namespace std;

class Test {
public:
  Test() {
    printf("Inside Test's Constructor\n");
  }

  ~Test(){
    printf("Inside Test's Destructor");
    getchar();
  }
};

int main() {
  static Test t1;  // Note that t1 is static

  exit(0);
}

输出:内部测试的构造函数
内部测试的构造函数


关闭文件实际上并不是退出时触发重要析构函数的好例子,因为无论如何程序退出时文件都会关闭。
温斯顿·埃韦特

1
@WinstonEwert:是的,但是可能存在仍然需要刷新的应用程序级缓冲区。
菲利普

1
这个问题在任何地方都没有提到C ++……
tdammers 2012年

我知道两种语言都不能原谅我,但是这个答案使我认为退出就像C#的failfast一样,所以在C ++中退出是否会在尝试执行finally之后?
吉米·霍法

@ JimmyHoffa,C ++没有finally
Winston Ewert

6

值得注意的是,C标准(C99)定义了两种类型的执行环境,即独立环境托管环境。独立式环境是一种不支持C库的C环境,适用于嵌入式应用程序等。支持C库的AC环境称为托管环境。

C99说,在独立环境中,程序终止是实现定义的。因此,如果实现定义mainreturn nexit,则它们的行为与该实现中定义的相同。

C99将托管环境行为定义为

如果主函数的返回类型是与之兼容的类型,则从初始调用到主函数的返回等同于以主函数返回的值作为参数来调用退出函数;到达终止主函数的}时将返回值0。如果返回类型与int不兼容,则未指定返回到主机环境的终止状态。


1
从独立环境中调用exit()确实没有任何意义。exit()的嵌入式等效项是将程序挂入一个永恒的循环,然后等待看门狗超时。

0

从C标准的角度来看,除了return作为语句和exit()函数之外,并非如此。这两种方法都会导致atexit()调用任何已注册的功能,然后终止程序。

您需要注意以下几种情况:

  • 递归main()。尽管在实践中很少见,但在C语言中是合法的。(C ++明确禁止这样做。)
  • 重复使用main()。有时,现有的main()将被重命名为其他名称,并被新的命名main()

exit()如果您在编写代码后发生了任何一种情况,则使用会引入一个错误,特别是如果没有异常终止时。为避免这种情况,养成将其main()视为现有功能并return在结束时使用的习惯是一个好主意。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.