оператор возврата против выхода () в main () - PullRequest
183 голосов
/ 20 января 2009

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

exit() делает что-то особенное, что return не делает?

Ответы [ 8 ]

264 голосов
/ 20 января 2009

На самом деле, есть разница, но она неуловима. Это имеет больше последствий для C ++, но различия важны.

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

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

Действуйте осторожно, предпочитая выход, а не возврат.

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

23 голосов
/ 20 января 2009

Другое отличие: exit - стандартная библиотека функция, поэтому вам нужно включить заголовки и связь со стандартом библиотека. Чтобы проиллюстрировать (в C ++), это действительная программа:

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, тогда непременно используйте его.

15 голосов
/ 02 мая 2011

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

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

5 голосов
/ 04 декабря 2014

Выполняет ли 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.

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

Портативная программа на С, похожая на эту:

#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 для выходных значений более нюансировано, чем нечетное / четное. На самом деле он использует что-то вроде младших трех битов для кодирования уровня серьезности. В целом, однако, уровни нечетной серьезности указывают на успех или различную информацию, а четные указывают на ошибки.

5 голосов
/ 27 июня 2011

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().

5 голосов
/ 20 января 2009

Я всегда использую 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
0 голосов
/ 23 мая 2019

Существует на самом деле разница между 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 - вам следует настроить его под свои нужды.

Говоря о С.

0 голосов
/ 21 мая 2019

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

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

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

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

...