Есть ли разница между return n
(в main
функции) и exit(n)
в C? Это определяется стандартами C или POSIX или зависит от ОС или компилятора?
В большинстве случаев нет никакой разницы, но вот программа на 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()
, но вы не должны зависеть от этого.)
Для 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 - использует возврат 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);
}
Вывод: внутри конструктора
теста внутри деструктора теста
finally
Стоит отметить, что стандарт C (C99) определяет два типа сред выполнения: автономная среда и размещенная среда . Автономная среда - это среда C, которая не поддерживает библиотеки C и предназначена для встроенных приложений и тому подобного. Среда AC, которая поддерживает библиотеки C, называется размещенной средой.
C99 говорит, что в автономной среде завершение программы определяется реализацией. Таким образом, если реализация определяет
main
,return n
иexit
их поведение такое, как определено в этой реализации.C99 определяет поведение размещенной среды как,
источник
С точки зрения стандарта Си, не совсем, кроме
return
того, чтобы быть оператором иexit()
быть функцией. Любая из них приведет к вызову любых функций, зарегистрированных с,atexit()
с последующим завершением программы.Есть несколько ситуаций, которые вы должны остерегаться:
main()
. Хотя это редко встречается на практике, это допустимо в C. (C ++ явно запрещает это.)main()
. Иногда существующееmain()
будет переименовано во что-то другое и будет вызвано новымmain()
.Использование
exit()
создаст ошибку, если что-то из этого произойдет после того, как вы написали код, особенно если не завершится ненормально. Чтобы избежать этого, полезно иметь привычку трактовать ееmain()
как функцию и использовать,return
когда вы хотите, чтобы она закончилась.источник