Return statement vs exit() в main()

Должен ли я использовать выражения exit() или просто return в main()? Лично я выступаю за выражения return, потому что я чувствую, что читаю какую-либо другую функцию, и управление потоком, когда я читаю код, является гладким (на мой взгляд). И даже если я хочу реорганизовать функцию main(), наличие return кажется лучшим выбором, чем exit().

Делает ли exit() что-нибудь особенное, что return не работает?

Ответ 1

Собственно, есть разница, но она тонкая. Это имеет большее значение для С++, но различия важны.

Когда я вызываю return в main(), деструкторы будут вызываться для моих локально локализованных объектов. Если я вызываю exit(), не будет вызван деструктор для моих локально локализованных объектов! Перечитайте это. exit() не возвращает. Это означает, что, как только я это называю, "нет спиннинга". Любые объекты, созданные вами в этой функции, не будут уничтожены. Часто это не имеет никакого значения, но иногда это происходит, например, закрытие файлов (конечно, вы хотите, чтобы все ваши данные были сброшены на диск?).

Обратите внимание, что объекты static будут очищены, даже если вы вызываете exit(). Наконец, обратите внимание, что если вы используете abort(), никакие объекты не будут уничтожены. То есть никакие глобальные объекты, статические объекты и никакие локальные объекты не будут вызваны их деструкторами.

Будьте осторожны, если предпочитаете выход с возвратом.

http://groups.google.com/group/gnu.gcc.help/msg/8348c50030cfd15a

Ответ 2

Еще одно отличие: exit - стандартная библиотека , поэтому вам необходимо включить заголовки и ссылки со стандартом библиотека. Чтобы проиллюстрировать (на С++) это действительная программа:

int main() { return 0; }

но для использования exit вам понадобится включить:

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

Плюс это добавляет дополнительное предположение: вызов exit из main имеет те же побочные эффекты, что и возврат нуля. Как указывали другие, это зависит от того, какой исполняемый файл вы создаете (т.е. Кто звонит main). Вы кодируете приложение, использующее C-runtime? Плагин майя? Служба Windows? Водитель? Для каждого случая потребуется исследование, чтобы убедиться, что exit эквивалентно return. ИМХО, используя exit, когда вы действительно имеете в виду return, просто делает код более запутанным. OTOH, если вы действительно имеете в виду exit, тогда обязательно используйте его.

Ответ 3

Есть по крайней мере одна причина, чтобы предпочесть exit: Если какой-либо из ваших обработчиков atexit ссылается на данные продолжительности хранения в режиме main или если вы использовали setvbuf или setbuf для назначения один из стандартных потоков - буфер продолжительности хранения в main, а затем возврат из main вызывает поведение undefined, но вызов exit действителен.

Другим потенциальным использованием (обычно зарезервированным для игрушечных программ) является выход из программы с рекурсивными вызовами main.

Ответ 4

Я всегда использую return, потому что стандартный прототип для main() говорит, что он возвращает int.

Тем не менее, некоторые версии стандартов предоставляют специальную обработку main и предполагают, что она возвращает 0, если нет явного выражения return. Учитывая следующий код:

int foo() {}
int main(int argc, char *argv[]) {}

g++ генерирует предупреждение только для foo() и игнорирует отсутствующий возврат из main:

% g++ -Wall -c foo.cc
foo.cc: In function ‘int foo()’:
foo.cc:1: warning: control reaches end of non-void function

Ответ 5

I STRONGLY второй комментарий Р. об использовании exit(), чтобы избежать автоматического восстановления в main() до того, как программа действительно закончится. Оператор return X; в main() не совсем эквивалентен вызову exit(X);, так как динамическое хранилище main() исчезает, когда возвращается main(), но оно не исчезает, если вызов exit() равен вместо этого.

Кроме того, в C или любом C-подобном языке оператор return сильно намекает читателю, что выполнение будет продолжаться в вызывающей функции, и хотя это продолжение выполнения обычно технически истинно, если вы считаете процедуру запуска C, которая называется вашей функцией main(), это не совсем то, что вы имеете в виду, когда хотите завершить процесс.

В конце концов, если вы хотите закончить свою программу из любой другой функции, кроме main(), вы должны позвонить exit(). Выполнение этой последовательности в main() также делает ваш код более читаемым, а также значительно упрощает преобразование вашего кода; то есть код, скопированный из main() в некоторую другую функцию, не будет ошибочным из-за случайных return операторов, которые должны были быть exit() вызовами.

Итак, объединяя все эти точки вместе, вывод заключается в том, что это плохая привычка, по крайней мере для C, использовать оператор return для завершения программы в main().

Ответ 6

Выполняет ли exit() что-нибудь особенное, что 'return' не делает?

С некоторыми компиляторами для необычных платформ exit() может перевести свой аргумент в значение выхода программы, а возврат из main() может просто передать значение непосредственно в среду хоста без какого-либо перевода.

Стандарт требует идентичного поведения в этих случаях (в частности, он говорит, что возвращает то, что int -совместимый с main() должен быть эквивалентен вызову exit() с этим значением). Проблема в том, что разные ОС имеют разные соглашения для интерпретации значений выхода. На многих (МНОГО!) Системах 0 означает успех, а что-то еще - провал. Но, скажем, VMS, нечетные значения означают успех и даже означают отказ. Если вы вернули 0 из main(), пользователь VMS увидел бы неприятное сообщение о нарушении доступа. На самом деле не было прав доступа - это было просто стандартное сообщение, связанное с кодом ошибки 0.

Затем ANSI пришел и благословил EXIT_SUCCESS и EXIT_FAILURE в качестве аргументов, которые вы могли бы передать на exit(). В стандарте также говорится, что exit(0) должен вести себя одинаково с exit(EXIT_SUCCESS), поэтому большинство реализаций определяют EXIT_SUCCESS на 0.

Таким образом, стандарт ставит вас в привязку к VMS, так как он не дает стандартного способа вернуть код сбоя, который имеет значение 0.

В начале 1990-х годов разработчик VAX/VMS C компилятор не интерпретировал возвращаемое значение из main(), он просто возвращал любое значение в среду хоста. Но если вы использовали exit(), он выполнил бы то, что требовалось стандартное: перевести EXIT_SUCCESS (или 0) в код успеха и EXIT_FAILURE в общий код отказа. Чтобы использовать EXIT_SUCCESS, вам нужно было передать его на exit(), вы не смогли бы вернуть его из main(). Я не знаю, сохранили ли более современные версии этого компилятора такое поведение.

Портативная программа C, используемая для этого:

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

int main() {
  printf("Hello, World!\n");
  exit(EXIT_SUCCESS);  /* to get good return value to OS */
  /*NOTREACHED*/ /* to silence lint warning */
  return 0;  /* to silence compiler warning */
}

Кроме того: если я правильно помню, соглашение VMS для значений выхода более тонкое, чем нечетное/четное. На самом деле он использует что-то вроде низких трех бит для кодирования уровня серьезности. Вообще говоря, однако, нечетные уровни серьезности указывали на успех или разную информацию, а четные - на ошибки.

Ответ 7

В C возврат из main - это то же самое, что вызов exit с тем же значением.

Раздел 5.1.2.2.3 стандарта C гласит:

Если возвращаемый тип основной функции является типом, совместимым с int, возврат из начального вызова основной функции эквивалентен вызову функции выхода со значением, возвращаемым главной функцией в качестве аргумента; 11) при достижении}, завершающего основную функцию, возвращается значение 0. Если возвращаемый тип не совместим с int, состояние завершения, возвращаемое в хост-среду, не указывается.

Правила для C++ немного отличаются, как упомянуто в других ответах.

Ответ 8

На самом деле есть разница между exit(0) и return(0) в main - когда ваша main функция вызывается несколько раз.

Следующая программа

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

int main(int argc, char** argv) {
  if (argc == 0)
    return(0);
  printf("%d", main(argc - 1, argv));
}

Беги как

./program 0 0 0 0

Результатом будет следующий вывод:

00000

Однако этот:

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

int main(int argc, char** argv) {
  if (argc == 0)
    exit(0);
  printf("%d", main(argc - 1, argv));
}

Не буду ничего печатать независимо от аргументов.

Если вы уверены, что никто никогда не назовет ваш main явно, это не является большой технической разницей в целом, но поддержание более четкого exit кода выглядело бы намного лучше. Если вы по какой-то причине хотите позвонить в main - вам следует настроить его под свои нужды.

Говоря о С.