Чи є різниця між return n
(у main
функції) і exit(n)
в C? Чи визначено це стандартами C або POSIX або це залежить від ОС або компілятора?
Чи є різниця між 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
Standard каже, що повернення від початкового виклику до основного є рівнозначним виклику виходу. Однак не можна очікувати, що повернення з основного не спрацює, якщо під час очищення можуть знадобитися дані, локальні до основних.
Для C ++
Коли вихід (0) використовується для виходу з програми, деструктори для нестатичних об'єктів, які охоплюються локально, не викликаються. Але деструктори викликаються, якщо використовується return 0.
Програма 1 - - використовує вихід (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);
}
Вихід: Конструктор
всередині тесту Тест-інструмент
finally
Варто відзначити, що стандарт C (C99) визначає два типи середовищ виконання, незалежне середовище та розміщене середовище . Окремо розташоване середовище - це середовище C, яке не підтримує бібліотеки С і призначене для вбудованих додатків тощо. Середовище змінного струму, яке підтримує бібліотеки С, називається середовищем розміщення.
C99 зазначає, що в окремо встановленому середовищі закінчення програми визначено реалізацією. Отже, якщо реалізація визначає main
, return n
і exit
, їх поведінка є такою, як визначено в цій реалізації.
C99 визначає поведінку навколишнього середовища як,
Якщо тип повернення основної функції - це сумісний з нею тип, повернення від початкового виклику до основної функції еквівалентно виклику функції виходу зі значенням, поверненим основною функцією як її аргументом; досягнення}, що завершує основну функцію, повертає значення 0. Якщо тип повернення не сумісний з int, статус припинення, повернутий у середовище хоста, не визначений.
З точки зору стандарту С, насправді, крім return
того, що це твердження та exit()
функція. Будь-яке atexit()
виклик будь-яких функцій, зареєстрованих з, викликається після закінчення програми.
Є кілька ситуацій, на які слід стежити:
main()
. Хоча це рідко зустрічається на практиці, він легальний у C. (C ++ прямо забороняє це.)main()
. Іноді існуючий main()
буде перейменований на щось інше і буде називатися новим main()
.Використання exit()
введе помилку, якщо будь-яка з них трапиться після того, як ви написали код, особливо якщо не закінчується аномально. Щоб уникнути цього, корисно мати звичку трактувати main()
як функцію, яку вона є, і використовувати, return
коли ви хочете, щоб вона закінчилася.