Что должно возвращать main () в C и C ++?

564
  • 24
    Я все еще думаю, что это тоже довольно расплывчато. Определите «самый эффективный» для меня. Эффективен в каком смысле? В смысле занимать меньше памяти? В смысле бегать быстрее? Я вижу полезные ответы, но я все еще думаю, что вопрос сформулирован довольно плохо.
  • 6
    В самом деле, контекст эффективного здесь очевиден, особенно с примерами (которые, вероятно, там проясняют определение «эффективный»). Надеюсь, бедный буфер не попал в дыру и не пожалел об этом полностью. Можно сказать, что независимо от void или int, возвращается значение, поэтому оно не влияет на размер файла, выполняемые операции и объем выделяемой памяти. И люди в большинстве операционных систем, как правило, возвращают 0 при успехе и что-то еще при - другом - успехе или неудаче - но стандарта нет. В конечном счете, нет никакой разницы в эффективности каким-либо очевидным способом.
Показать ещё 6 комментариев
Теги:
return-value
return-type
main

20 ответов

497
Лучший ответ

Возвращаемое значение для main должно указывать, как вышла программа. Нормальный выход обычно представлен возвращаемым значением 0 от main. Аномальное завершение обычно сигнализируется ненулевым возвратом, но нет стандарта для интерпретации ненулевых кодов. Также, как отмечают другие, void main() явно запрещен стандартом С++ и не должен использоваться. Действительными сигналами С++ main являются:

int main()

и

int main(int argc, char* argv[])

что эквивалентно

int main(int argc, char** argv)

Также стоит отметить, что в С++ int main() может быть оставлено без возвращаемого значения, после которого оно по умолчанию возвращает 0. Это также верно для программы C99. Нужно ли исключать возвращение 0 или нет, открыто для обсуждения. Диапазон действительных сигнатур основных программ C намного больше.

Кроме того, эффективность не связана с функцией main. Его можно вводить и оставлять один раз (маркирование запуска и завершения программы) в соответствии со стандартом С++. Для C случай отличается, и повторный ввод main() разрешен, но его, вероятно, следует избегать.

  • 60
    main МОЖЕТ быть введен / оставлен несколько раз, но эта программа, вероятно, не получит никаких наград за дизайн;)
  • 10
    C99 также имеет ошибочную особенность C ++, заключающуюся в том, что достижение конца функции main () эквивалентно возвращению 0 - если main () определено для возврата типа, совместимого с int (раздел 5.1.2.2.3).
Показать ещё 19 комментариев
144

Принятый ответ кажется нацеленным на С++, поэтому я решил добавить ответ, относящийся к C, и это несколько отличается.

ISO/IEC 9899: 1989 (C90):

main() должен быть объявлен как:

int main(void)
int main(int argc, char **argv)

Или эквивалентно. Например, int main(int argc, char *argv[]) эквивалентен второму. Кроме того, возвращаемый тип int может быть опущен, поскольку он по умолчанию.

Если реализация позволяет это, main() может быть объявлен другими способами, но это делает реализацию программы определенной и более строго не соответствует.

Стандарт определяет 3 значения для возвращаемого значения, которые строго соответствуют (то есть не зависят от поведения, определенного реализацией): 0 и EXIT_SUCCESS для успешного завершения и EXIT_FAILURE для неудачного завершения. Любые другие значения являются нестандартными, а реализация определена. main() должен иметь явный оператор return в конце, чтобы избежать поведения undefined.

Наконец, нет ничего неправильного с точки зрения стандартов с вызовом main() из программы.

ISO/IEC 9899: 1999 (C99):

Для C99 все то же, что и выше, кроме:

  • Возвращаемый тип int не может быть опущен.
  • Вы можете опустить оператор return из main(). Если вы это сделаете, и main() закончен, есть неявный return 0.
  • 0
    @ Крис Янг: Где будет возвращаемое значение. И в чем польза возвращаемого значения? Можете ли вы объяснить это. или это просто, чтобы избежать неопределенного поведения.
  • 0
    @ MELWIN: Возвращаемое значение передается в хост-среду. В большинстве случаев это будет ваша ОС, которая может передавать это значение другому запущенному процессу по запросу (например, вызову system ()).
Показать ещё 9 комментариев
99

Стандартная C - размещенная среда

Для размещенной среды (обычной), стандарт C11 (ISO/IEC 9899: 2011) гласит:

5.1.2.2.1 Запуск программы

Функция, вызванная при запуске программы, называется main. Реализация не объявляет прототип для этой функции. Он определяется с типом возврата int и без Параметры:

int main(void) { /* ... */ }

или с двумя параметрами (называемыми здесь argc и argv, хотя любые имена могут быть используются, поскольку они являются локальными для функции, в которой они объявлены):

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

или эквивалент; 10) или каким-либо другим способом реализации.

Если они объявлены, параметры главной функции должны подчиняться следующим Ограничения:

  • Значение argc должно быть неотрицательным.
  • argv[argc] должен быть нулевым указателем.
  • Если значение argc больше нуля, элементы массива argv[0] через argv[argc-1] включительно должны содержать указатели на строки, которые указаны определяемые реализацией значения среды хоста перед запуском программы. Цель состоит в том, чтобы предоставить информацию о программе, определенную до запуска программы из другого места в размещенной среде. Если хост-среда не способна снабжая строки буквами в верхнем и нижнем регистре, реализация должен гарантировать, что строки принимаются в нижнем регистре.
  • Если значение argc больше нуля, строка, на которую указывает argv[0]представляет собой название программы; argv[0][0] должен быть нулевым символом, если имя программы недоступно из среды хоста. Если значение argc равно больше единицы, строки, на которые указывает argv[1] через argv[argc-1]представляют параметры программы.
  • Параметры argc и argv, а строки, на которые указывает массив argv, должны могут быть модифицированы программой и сохраняют свои последние сохраненные значения между программой запуск и завершение программы.

10) Таким образом, int можно заменить на имя typedef, определенное как int, или тип argv может быть записан как char **argv и т.д.

Окончание программы на C99 или C11

Значение, возвращаемое из main(), передается в "среду" определенным образом.

5.1.2.2.3 Окончание программы

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

11) В соответствии с 6.2.4 времена жизни объектов с автоматическим временем хранения, объявленные в mainзакончится в первом случае, даже если они не были бы в последнем.

Обратите внимание, что 0 определяется как "успех". Вы можете использовать EXIT_FAILURE и EXIT_SUCCESS из <stdlib.h>, если хотите, но 0 хорошо установлено, а также 1. См. Также Коды выхода более 255 - возможно?.

В C89 (и, следовательно, в Microsoft C) нет утверждения о том, что произойдет, если функция main() возвращает, но не указывает возвращаемое значение; поэтому он приводит к поведению undefined.

7.22.4.4 Функция exit

¶5 Наконец, управление возвращается в среду хоста. Если значение status равно нулю или EXIT_SUCCESS, возвращается форма завершения успешного завершения статуса. Если значение status равно EXIT_FAILURE, возвращается форма определения неудачного завершения статуса. В противном случае возвращаемый статус определяется реализацией.

Стандартная С++ - размещенная среда

В стандарте С++ 11 (ISO/IEC 14882: 2011) говорится:

3.6.1 Основная функция [basic.start.main]

¶1 Программа должна содержать глобальную функцию main, которая является назначенным началом программы. [...]

¶2 Реализация не должна предопределять основную функцию. Эта функция не должна быть перегружена. Он должен имеют тип возвращаемого типа int, но в противном случае его тип определяется реализацией. Все реализации должны допускать оба следующих определения main:

int main() { /* ... */ }

и

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

В последнем виде argc должно быть количество аргументов, переданных программе из среды в котором запущена программа. Если argc отличен от нуля, эти аргументы должны быть представлены в argv[0]через argv[argc-1] в качестве указателей на начальные символы многобайтовых строк с нулевым завершением (NTMBS) (17.5.2.1.4.2) и argv[0] должен быть указателем на начальный символ NTMBS, который представляет имя, используемое для вызова программы или "". Значение argc должно быть неотрицательным. Значение argv[argc]должно быть равно 0. [Примечание: после argv рекомендуется добавлять дополнительные (необязательные) параметры. -конец примечание]

¶3 Функция main не должна использоваться в программе. Связь (3.5) of main определяется реализацией. [...]

¶5 Оператор возврата в основном имеет эффект отхода от основной функции (уничтожение любых объектов с помощью автоматического время хранения) и вызов std::exit с возвращаемым значением в качестве аргумента. Если контроль достигнет цели из основного, не встречая оператора return, эффект заключается в выполнении

return 0;

В стандарте С++ явно говорится: "Он [главная функция] должен иметь тип возвращаемого типа int, но в противном случае его тип определяется реализацией", и для него требуются те же две подписи, что и стандарт C, как параметры, Таким образом, "void main()" напрямую не разрешен стандартом С++, хотя он ничего не может сделать, чтобы остановить нестандартную реализацию, позволяющую альтернативы. Обратите внимание, что С++ запрещает пользователю вызывать main (но стандарт C нет).

В стандарте С++ 11 есть абзац §18.5 Начало и завершение, которое идентично абзацу из §7.22.4.4 Функция exit в стандарт C11 (приведенный выше), кроме сноски (которая просто документирует, что EXIT_SUCCESS и EXIT_FAILURE определены в <cstdlib>).

Стандартное C - общее расширение

Классически системы Unix поддерживают третий вариант:

int main(int argc, char **argv, char **envp) { ... }

Третий аргумент - это список указателей на строки с нулевым завершением, каждый из которых является переменной среды, которая имеет имя, знак равенства и значение (возможно, пустое). Если вы не используете это, вы все равно можете добраться до среды с помощью extern char **environ;. В течение долгого времени у этого не было заголовка, который его объявил, но POSIX 2008 теперь требует, чтобы он был объявлен в <unistd.h>.

Это признается стандартом C как общее расширение, задокументированное в Приложении J:

J.5.1 Аргументы среды

¶1 В размещенной среде основная функция получает третий аргумент, char *envp[], который указывает на набор указателей с нулевым завершением на char, каждый из которых указывает на строку который предоставляет информацию об окружающей среде для этого выполнения программы (5.1.2.2.1).

Microsoft C

Интересен компилятор Microsoft VS 2010. На веб-сайте говорится:

Синтаксис объявления для main

 int main();

или, необязательно,

int main(int argc, char *argv[], char *envp[]);

В качестве альтернативы функции main и wmain могут быть объявлены как возвращающие void (без возвращаемого значения). Если вы объявляете main или wmain как возвращающий void, вы не можете вернуть код выхода в родительский процесс или операционную систему с помощью оператора return. Чтобы вернуть код выхода, когда main или wmain объявлен как void, вы должны использовать функцию exit.

Мне непонятно, что происходит (какой код выхода возвращается родительскому или ОС), когда программа с void main() завершает работу - и веб-сайт MS также отключается.

Интересно, что MS не предписывает версию с двумя аргументами main(), которую требуют стандарты C и С++. Он только предписывает форму трех аргументов, где третий аргумент char **envp, указатель на список переменных среды.

На странице Microsoft также перечислены некоторые другие альтернативы - wmain(), которые принимают широкие строки символов и некоторые другие.

Microsoft Visual Studio 2005 версия эта страница не перечисляет void main() в качестве альтернативы. версии из Microsoft Visual Studio 2008 и далее.

Стандартная C - независимая среда

Как отмечалось ранее, требования, изложенные выше, применяются к размещенным средам. Если вы работаете с автономной средой (которая является альтернативой размещенной среде), то в стандарте гораздо меньше сказать. Для автономной среды функцию, вызванную при запуске программы, не нужно называть main, и нет ограничений на ее возвращаемый тип. В стандарте говорится:

5.1.2 среды выполнения

Определены две среды исполнения: автономные и размещенные. В обоих случаях, запуск программы происходит, когда назначенная функция C вызывается выполнением Окружающая среда. Перед запуском программы все объекты со статическим временем хранения должны быть инициализированы (установлены на их начальные значения). Способ и время такой инициализации в противном случае не определены. Окончание программы возвращает управление среде выполнения.

5.1.2.1 Свободная среда

В автономной среде (в которой выполнение программы C может иметь место без какой-либо выгоды от операционной системы), имя и тип функции, вызываемой при запуске программы, определяются в соответствии с реализацией. Любые библиотечные средства, доступные для автономной программы, отличные от минимального набора, требуемого в соответствии с разделом 4, определяются реализацией.

Эффект завершения программы в автономной среде определяется реализацией.

Перекрестная ссылка к разделу 4 Соответствие означает следующее:

¶5 Строго соответствующая программа должна использовать только те функции языка и библиотеки, которые указаны в настоящем стандарте. 3) Он не должен производить вывод, зависящий от каких-либо неуказанных, undefined или реализации -пределенное поведение и не должно превышать минимального предела реализации.

¶6 Две формы согласованной реализации размещены и автономны. Соответствующая хостинговая реализация должна принимать любую строго соответствующую программу. Соответствующая независимая реализация должна принимать любую строго соответствующую программу, в которой использование функций, указанных в разделе библиотеки (раздел 7), ограничивается содержимым стандартных заголовков <float.h>, <iso646.h>, <limits.h>, <stdalign.h>, <stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h> и <stdnoreturn.h>. Соответствующая реализация может иметь расширения (в том числе дополнительные функции библиотеки) при условии, что они не изменяют поведение любой строго соответствующей программы. 4)

¶7 Соответствующая программа является приемлемой для соответствующей реализации. 5)

3) Строго соответствующая программа может использовать условные функции (см. 6.10.8.3), если использование защищено соответствующей условной инструкцией по предварительной обработке включения с использованием соответствующего макроса. Например:

#ifdef __STDC_IEC_559__ /* FE_UPWARD defined */
    /* ... */
    fesetround(FE_UPWARD);
    /* ... */
#endif

4) Это означает, что соответствующая реализация не содержит идентификаторов, отличных от тех, которые явно зарезервированы в этом международном стандарте.

5) Строго совместимые программы должны быть максимально переносимыми между соответствующими реализациями. Соответствующие программы могут зависеть от непереносимых функций соответствующей реализации.

Заметно, что единственным заголовком, требуемым для автономной среды, которая фактически определяет любые функции, является <stdarg.h> (и даже те, которые могут быть и часто являются просто макросами).

Стандартная С++ - Свободная среда

Так же, как стандарт C распознает как размещенную, так и автономную среду, так же, как и стандарт С++. (Цитаты из ИСО/МЭК 14882: 2011.)

1.4 Соответствие требованиям [intro.compliance]

¶7 Определены два вида реализации: размещенная реализация и самостоятельная реализация. Для размещенной реализации этот международный стандарт определяет набор доступных библиотек. Свободный реализация - это та, в которой выполнение может выполняться без использования операционной системы и имеет набор библиотек, поддерживающих реализацию, которые содержат определенные библиотеки поддержки языков (17.6.1.3).

¶8 Соответствующая реализация может иметь расширения (включая дополнительные библиотечные функции) при условии, что они не изменят поведение какой-либо хорошо сформированной программы. Реализации необходимы для диагностики программ, которые используйте такие расширения, которые плохо сформированы в соответствии с настоящим Международным стандартом. Однако, сделав это, они могут компилировать и выполнять такие программы.

¶9 Каждая реализация должна включать документацию, которая идентифицирует все условно поддерживаемые конструкции, которые она не поддерживает, и определяет все специфические для локали характеристики. 3

3) В этой документации также определяется поведение, определяемое реализацией; см. 1.9.

17.6.1.3 Внештатные реализации [соответствие]

Определены два вида реализации: хостинг и автономный (1.4). Для размещенной реализации этот международный стандарт описывает набор доступных заголовков.

Внештатная реализация имеет набор заголовков, определенный реализацией. Этот набор должен включать по крайней мере заголовки, показанные в таблице 16.

Прилагаемая версия заголовка <cstdlib> должна объявлять, по крайней мере, функции abort, atexit, at_quick_exit, exit и quick_exit (18.5). Другие заголовки, перечисленные в этой таблице, должны соответствовать тем же требованиям, что и для размещенной реализации.

Таблица 16 - Заголовки С++ для автономных реализаций

Subclause                           Header(s)
                                    <ciso646>
18.2  Types                         <cstddef>
18.3  Implementation properties     <cfloat> <limits> <climits>
18.4  Integer types                 <cstdint>
18.5  Start and termination         <cstdlib>
18.6  Dynamic memory management     <new>
18.7  Type identification           <typeinfo>
18.8  Exception handling            <exception>
18.9  Initializer lists             <initializer_list>
18.10 Other runtime support         <cstdalign> <cstdarg> <cstdbool>
20.9  Type traits                   <type_traits>
29    Atomics                       <atomic>

Как насчет использования int main() в C?

Стандарт §5.1.2.2.1 стандарта C11 показывает предпочтительную нотацию - int main(void) - но в стандарте есть также два примера, которые показывают int main(): §6.5.3.4 ¶8 и §6.7.6.3 ¶20. Теперь важно отметить, что примеры не являются "нормативными"; они являются лишь иллюстративными. Если в примерах есть ошибки, они не влияют непосредственно на основной текст стандарта. Тем не менее, они сильно свидетельствуют о ожидаемом поведении, поэтому, если стандарт включает в себя int main() в примере, он предполагает, что int main() не запрещен, даже если он не является предпочтительным обозначением.

6.5.3.4 Операторы sizeof и _Alignof

...

¶8 ПРИМЕР 3 В этом примере размер массива переменной длины вычисляется и возвращается из функции:

#include <stddef.h>

size_t fsize3(int n)
{
    char b[n+3]; // variable length array
    return sizeof b; // execution time sizeof
}
int main()
{
    size_t size;
    size = fsize3(10); // fsize3 returns 13
    return 0;
}
  • 0
    В соответствии с §6.7.6.3 / 14 Стандарта C11 (чуть выше одного из приведенных вами примеров) «Пустой список в деклараторе функции, который является частью определения этой функции, указывает на то, что функция не имеет параметров». Кажется, это указывает на то, что int main() {} - это нормально, так как это декларатор, который является частью определения функции.
  • 0
    @DavidBowling: определение функции наподобие int main(){ … } действительно указывает, что функция не принимает аргументов, но не предоставляет прототип функции, AFAICT. Для main() это редко проблема; это означает, что если у вас есть рекурсивные вызовы main() , аргументы проверяться не будут. Для других функций это большая проблема - вам действительно нужен прототип в области видимости при вызове функции, чтобы убедиться, что аргументы верны.
Показать ещё 3 комментария
56

Я считаю, что main() должен возвращать либо EXIT_SUCCESS, либо EXIT_FAILURE. Они определены в stdlib.h

  • 2
  • 20
    0 тоже стандартно.
Показать ещё 7 комментариев
27

Обратите внимание, что стандарты C и С++ определяют два типа реализаций: автономный и размещенный.

  • среда с поддержкой C90

    Допустимые формы 1:

    int main (void)
    int main (int argc, char *argv[])
    
    main (void)
    main (int argc, char *argv[])
    /*... etc, similar forms with implicit int */
    

    Комментарии:

    Первые два явно указаны как допустимые формы, другие неявно разрешены, потому что C90 допускает "неявный int" для возвращаемого типа и параметров функции. Никакая другая форма не разрешена.

  • Свободная среда C90

    Разрешена любая форма или название main 2.

  • C99 размещенная среда

    Допустимые формы 3:

    int main (void)
    int main (int argc, char *argv[])
    /* or in some other implementation-defined manner. */
    

    Комментарии:

    C99 удалил "неявный int", поэтому main() больше не действителен.

    Было введено странное, неоднозначное предложение "или каким-то другим способом, определяемым реализацией". Это может быть интерпретировано как "параметры int main() могут меняться" или как "main может иметь любую определенную реализацию форму".

    Некоторые компиляторы решили интерпретировать стандарт последним. Можно утверждать, что нельзя легко утверждать, что они не строго соответствуют, ссылаясь на стандарт сам по себе, так как он неоднозначен.

    Однако, чтобы разрешить полностью дикие формы main(), вероятно, (?) не было намерения этого нового предложения. Обоснование C99 (не нормативное) подразумевает, что предложение относится к дополнительным параметрам к int main 4.

    Тем не менее, раздел для завершения программы для среды размещаемой среды продолжает рассуждать о том, что main не возвращает int 5. Хотя этот раздел не является нормативным для того, как следует объявлять основную информацию, это, безусловно, подразумевает, что main может быть объявлен полностью определенным образом даже в размещенных системах.

  • Свободная среда C99

    Разрешена любая форма или название main 6.

  • среда с включенным C11

    Допустимые формы 7:

    int main (void)
    int main (int argc, char *argv[])
    /* or in some other implementation-defined manner. */
    
  • Свободная среда C11

    Разрешена любая форма или название main 8.


Обратите внимание, что int main() никогда не указывалось в качестве допустимой формы для любой размещенной реализации C в любой из вышеперечисленных версий. В C, в отличие от С++, () и (void) имеют разные значения. Первый - устаревшая функция, которая может быть удалена с языка. См. Дальнейшие языковые направления C11:

6.11.6 Объявление функций

Использование деклараторов функций с пустыми скобками (не деклараторы типов параметров прототипа) является устаревшей функцией.


  • размещенная среда С++ 03

    Допустимые формы 9:

    int main ()
    int main (int argc, char *argv[])
    

    Комментарии:

    Обратите внимание на пустую скобку в первой форме. С++ и C в этом случае разные, потому что в С++ это означает, что функция не принимает никаких параметров. Но в C это означает, что он может принимать любой параметр.

  • Свободная среда С++ 03

    Имя функции, вызываемой при запуске, определяется реализацией. Если он называется main(), он должен следовать заявленным формам 10:

    // implementation-defined name, or 
    int main ()
    int main (int argc, char *argv[])
    
  • Среда размещения на С++ 11

    Допустимые формы 11:

    int main ()
    int main (int argc, char *argv[])
    

    Комментарии:

    Текст стандарта был изменен, но он имеет то же значение.

  • Свободная среда С++ 11

    Имя функции, вызываемой при запуске, определяется реализацией. Если он называется main(), он должен следовать указанным формам 12:

    // implementation-defined name, or 
    int main ()
    int main (int argc, char *argv[])
    

Ссылки

  • ANSI X3.159-1989 2.1.2.2 Хостинговая среда. "Запуск программы"

    Функция, вызванная при запуске программы, называется main. реализация не объявляет прототипа для этой функции. Это должно быть определяемый с типом возврата int и без параметров:

    int main(void) { /* ... */ } 
    

    или с двумя параметрами (здесь argc и argv, хотя любые имена могут использоваться, поскольку они являются локальными для функция, в которой они объявлены):

    int main(int argc, char *argv[]) { /* ... */ }
    
  • ANSI X3.159-1989 2.1.2.1 Внештатная среда:

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

  • ISO 9899: 1999 5.1.2.2 Хостинговая среда → 5.1.2.2.1 Запуск программы

    Функция, вызванная при запуске программы, называется main. реализация не объявляет прототипа для этой функции. Это должно быть определяемый с типом возврата int и без параметров:

    int main(void) { /* ... */ } 
    

    или с двумя параметрами (здесь argc и argv, хотя любые имена могут использоваться, поскольку они являются локальными для функция, в которой они объявлены):

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

    или эквивалент; 9) или в некоторых других реализациях образом.

  • Обоснование международного стандарта - Языки программирования - C, редакция 5.10. 5.1.2.2 Хостинговая среда → 5.1.2.2.1 Запуск программы

    Поведение аргументов main, а также взаимодействие выхода, main и atexit (см. §7.20.4.2) был кодифицирован, чтобы обуздать некоторое нежелательное многообразие в представлении argv строки и значения значений, возвращаемых main.

    Спецификация argc и argv в качестве аргументов main признает обширную предыдущую практику. argv [argc] требуется, чтобы он был нулевым указателем, чтобы обеспечить избыточную проверку для конца списка, также на основе обычной практики.

    main - единственная функция, которая может быть объявлена ​​с возможностью переносимости с нулевым или двумя аргументами. (Количество аргументов других функций должно точно совпадать между вызовом и определением.) Этот специальный случай просто признает распространенную практику отказа от аргументов main, когда программа не имеет доступа к строкам аргументов программы. Хотя многие реализации поддерживают более двух аргументов в основном, такая практика не поддерживается и не запрещена Стандартом; программа, определяющая main с тремя аргументами, строго не соответствует (см. §J.1.1.).

  • ISO 9899: 1999 5.1.2.2 Хостинговая среда → 5.1.2.2.3 Окончание программы

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

  • ISO 9899: 1999 5.1.2.1 Внештатная среда

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

  • ISO 9899: 2011 5.1.2.2 Хостинг-среда → 5.1.2.2.1 Запуск программы

    Этот раздел идентичен приведенному выше C99.

  • ISO 9899: 1999 5.1.2.1 Внештатная среда

    Этот раздел идентичен приведенному выше C99.

  • ISO 14882: 2003 3.6.1 Основная функция

    Реализация не должна предопределять основную функцию. Эта функция не должна быть перегружена. Он должен иметь тип возвращаемого типа int, но в противном случае его тип определяется реализацией. Все реализации должны допускать оба следующих определения main:

    int main() { /* ... */ }
    

    и

    int main(int argc, char* argv[]) { /* ... */ }
    
  • ISO 14882: 2003 3.6.1 Основная функция

    Определяется реализацией, требуется ли программа в автономной среде для определения основной функции.

  • ISO 14882: 2011 3.6.1 Основная функция

    Реализация не должна предопределять основную функцию. Эта функция не должна быть перегружена. Он должен иметь тип возвращаемого типа int, но в противном случае его тип определяется реализацией. Все реализации должны разрешить как

    - функция(), возвращающая int и

    - функция (int, указатель на указатель на char), возвращающая int

    как тип основного (8.3.5).

  • ISO 14882: 2011 3.6.1 Основная функция

    Этот раздел идентичен приведенному выше С++ 03.

  • 0
    Один вопрос: означают ли стандарты C ++, что сигнатура функции запуска в автономных средах также определяется реализацией? Например, реализация могла бы определить функцию запуска: int my_startup_function () или int my_startup_function (int argc, char *argv[]) но может иметь, например: char my_startup_function (long argc, int *argv[]) в качестве функции запуска, а? Я думаю, нет, верно? Кроме того, разве это не так двусмысленно?
  • 0
    @Utku Может иметь любую подпись, если она не названа main() потому что тогда она должна использовать одну из перечисленных подписей. Я полагаю, что наиболее распространенным из них будет void my_startup_function () , так как нет смысла возвращаться из программы на автономных системах.
Показать ещё 3 комментария
26

Возврат 0 при успехе и ненулевое значение для ошибки. Это стандарт, используемый сценариями UNIX и DOS, чтобы узнать, что произошло с вашей программой.

7

Имейте в виду, что даже если вы возвращаете int, некоторые ОС (Windows) обрезают возвращаемое значение на один байт (0-255).

  • 4
    Unix делает то же самое, что и большинство других операционных систем, вероятно. Я знаю, что VMS делает такие невероятные странные вещи, что возвращение чего-либо, кроме EXIT_SUCCESS или EXIT_FAILURE, вызывает проблемы.
  • 1
    MSDN требует отличия: при сообщении через mscorlib код выхода представляет собой 32-разрядное целое число со знаком . Кажется, это подразумевает, что библиотеки времени выполнения C, которые усекают коды выхода, являются дефектными.
Показать ещё 1 комментарий
6

main() в C89 и K & R C неопределенные типы возврата по умолчанию для int.

return 1? return 0?
  • Если вы не пишете оператор return в int main(), закрывающий { по умолчанию возвращает 0.

  • return 0 или return 1 будет получен родительским процессом. В оболочке он переходит в переменную оболочки, и если вы используете свою программную форму в оболочке и не используете эту переменную, вам не нужно беспокоиться о возвращаемом значении main().

Смотрите Как я могу получить возвращаемую мою главную функцию?.

$ ./a.out
$ echo $?

Таким образом вы можете видеть, что это переменная $?, которая получает младший значащий байт возвращаемого значения main().

В сценариях Unix и DOS обычно возвращаются return 0 на успех и ненулевое значение для ошибки. Это стандарт, используемый сценариями Unix и DOS, чтобы узнать, что произошло с вашей программой и контролировать весь поток.

  • 4
    Строго говоря, $? не является переменной среды; это предопределенная (или встроенная) переменная оболочки. Трудно заметить разницу, но если вы запустите env (без каких-либо аргументов), он напечатает окружение, а $? не будет отображаться в окружающей среде.
  • 1
    Возврат 0 автоматически, когда основные "падения конца" только в C ++ и C99, а не в C90.
4

Возвращаемое значение может использоваться операционной системой для проверки того, как программа была закрыта.

Возвращаемое значение 0 обычно означает "ОК" в большинстве операционных систем (те, о которых я могу думать в любом случае).

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

Это НЕ только соглашение о программировании.

  • 0
    В этом вопросе нет ничего, что указывало бы на наличие оперативной системы. Возврат значения не имеет никакого смысла в автономной системе.
3

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

  • 1
    Это комментарий, а не ответ на вопрос.
2

Возврат 0 должен сообщить программисту, что программа успешно завершила задание.

  • 0
    Возвращение 1 из main() обычно сигнализирует об ошибке; возвращает 0 сигналов успеха. Если ваши программы всегда терпят неудачу, тогда 1 в порядке, но это не лучшая идея.
  • 1
    @JonathanLeffler: значение возврата 1 из main определяется реализацией. Единственные языковые значения: 0 , EXIT_SUCCESS (часто определяется как 0 ) и EXIT_FAILURE . В OpenVMS return 1; обозначает успешное завершение.
Показать ещё 1 комментарий
2

У меня создалось впечатление, что стандарт указывает, что main не нуждается в возвращаемом значении, поскольку успешное возвращение было основано на ОС (ноль в одном может быть успешным или неудачным в другом), поэтому отсутствие возврата было cue для компилятора, чтобы вставить успешное возвращение.

Однако я обычно возвращаю 0.

  • 0
    C99 (и C ++ 98) позволяют вам опустить оператор return из main; C89 не позволяет вам опустить оператор возврата.
  • 0
    Это комментарий, а не ответ.
Показать ещё 2 комментария
1

В С++ основная функция должна быть объявлена ​​как int main(), а не void main(), поскольку компилятор затем выдает ошибку в случае void main. Основная функция может принимать любое количество аргументов, таких как int main (int k, int l, int arr []) или int main (void).

#include <iostream>
using namespace std;

int main(void) {
    // your code goes here
    cout<<"a";
    return 0;
}

Вывод:

Success #stdin #stdout 0s 4416KB
a

Прибывая в возвращаемую часть, он должен вернуть только 0, иначе компилятор выдает ошибку. например, если вы вернете 1, вы получите желаемый результат, но он также выдает ошибку времени выполнения.

Пример

#include <iostream>
using namespace std;

int main(int k,float m,char g, int arr[]) {
    // your code goes here
    k=0;
    cout<<k;
    g='a';
    cout<<g;
    cout<<"a";
    return 1;
}

Вывод:

Runtime error   #stdin #stdout 0s 4448KB
0aa
  • 1
    Это неправда. В C ++ основная функция имеет только указанные формы или формы, определяемые реализацией. Основная функция, принимающая any number of arguments верна только в тех реализациях, которые ее поддерживают, которые могут быть любой формы, также возвращая что-то отличное от int. Вы можете вернуть любое значение типа int из main, используя стандартные определенные формы, которые впоследствии обычно интерпретируются базовой операционной системой.
  • 2
    "[I] t должен возвращать только 0, иначе компилятор выдаст ошибку." Нет, компилятор не выдаст вам за это ошибку. «[Если] вы вернете 1, вы получите желаемый результат, но он также выдаст ошибку времени выполнения». Я не знаю, в какой среде вы запускаете вашу программу, и она может сообщать ненулевые значения выхода, но в целом это утверждение неверно.
1

Что нужно вернуть, зависит от того, что вы хотите сделать с исполняемым файлом. Например, если вы используете вашу программу с оболочкой командной строки, то вам нужно вернуть 0 для успеха и не равен нулю для отказа. Тогда вы сможете использовать программу в оболочках с условной обработкой в ​​зависимости от результата вашего кода. Также вы можете назначить любое ненулевое значение в соответствии с вашей интерпретацией, например, для критических ошибок разные точки выхода программы могут заканчивать программу с разными значениями выхода и которая доступна вызывающей оболочке, которая может решить, что делать, проверяя возвращаемое значение. Если код не предназначен для использования с оболочками, а возвращаемое значение никого не беспокоит, тогда оно может быть опущено. Я лично использую подпись int main (void) { .. return 0; .. }

  • 0
    Формат main () определяется реализацией, то есть компилятором. Программист не может выбрать, какую форму выбрать, кроме случаев, когда компилятор поддерживает несколько форм.
  • 0
    @Lundin Возвращаемый тип будет реализацией реализацией. Но значение, которое должно быть возвращено, определяется программистом. C99 Раздел 5.1.2.2.3 упоминает, что возвращаемый тип main совместим с int . Поэтому возвращение int не будет проблемой. Хотя допускаются и другие возвращаемые типы, но в этом случае переменная среды, имеющая возвращаемое значение, не будет указана. Но если программист return 0; затем в bash его можно использовать для создания веток.
1

Если у вас действительно есть проблемы, связанные с эффективностью возврата целого из процесса, вы, вероятно, должны избегать многократного вызова этого процесса, чтобы это возвращаемое значение стало проблемой.

Если вы это делаете (вызывается процесс столько раз), вы должны найти способ разместить свою логику непосредственно внутри вызывающего или в DLL файле, не выделяя определенный процесс для каждого вызова; множественные распределения процессов приносят вам соответствующую проблему с эффективностью в этом случае.

В деталях, если вы хотите узнать, является ли возврат 0 более или менее эффективным, чем возврат 1, в некоторых случаях это может зависеть от компилятора, но в общем случае, если они считываются из одного источника (локального, константа, встроенная в код, результат функции и т.д.), она требует точно такого же количества тактовых циклов.

0

Каков правильный (наиболее эффективный) способ определения функции main() в C и С++ - int main() или void main() - и почему?

Эти слова "(наиболее эффективные)" не меняют вопрос. Если вы не находитесь в автономной среде, есть один универсально правильный способ объявить main(), а это как возвращение int.

Что должно main() возвращаться в C и С++?

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

Если int main() возвращает 1 или возвращает 0?

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

0

Опустить return 0

Когда программа C или С++ достигает конца main, компилятор автоматически сгенерирует код для возврата 0, поэтому нет необходимости помещать return 0; явно в конце main.

Примечание:, когда я делаю это предложение, он почти всегда сопровождается одним из двух видов комментариев: "Я этого не знал". или "Это плохой совет!" Мое обоснование заключается в том, что безопасно и полезно полагаться на поведение компилятора, явно поддерживаемое стандартом. Для C, поскольку C99; см. раздел 5.1.2.2.3 стандарта ISO/IEC 9899: 1999:

[...] возврат от начального вызова к функции main эквивалентен вызову функции exit со значением, возвращаемым функцией main в качестве аргумента; достижение }, которое завершает функцию main, возвращает значение 0.

Для С++, начиная с первого стандарта в 1998 году; см. раздел ИСО/МЭК 14882: 1998 раздел 3.6.1:

Если элемент управления достигнет конца main без столкновения с оператором return, эффект будет выполняться при возврате 0;

Все версии обоих стандартов с тех пор (C99 и С++ 98) поддерживают ту же идею. Мы полагаемся на автоматически сгенерированные функции-члены в С++, и немногие люди пишут явные инструкции return; в конце функции void. Причины против пропусков, похоже, сводятся к "это выглядит странно" . Если, как и я, вам будет интересно узнать о причине изменения стандарта C прочитать этот вопрос. Также обратите внимание, что в начале 1990-х годов это считалось "неряшливой практикой", поскольку в то время это было undefined (хотя и широко поддерживается).

Поэтому я защищаю его; другие не согласны (часто яростно!) В любом случае, если вы столкнетесь с кодом, который его не выпускает, вы будете знать, что он явно поддерживается стандартом, и вы узнаете, что это значит.

  • 0
    Примечание . Цель этого ответа - дать возможность тем из нас, кто часто дает этот совет по CodeReview, ответ StackOverflow, на который мы можем указать в отношении практики пропуска return 0;
  • 0
    Это плохой совет, потому что компиляторы, которые реализуют только C89, а не какой-либо более поздний стандарт, все еще чрезвычайно распространены (я пишу это в 2017 году) и останутся чрезвычайно распространенными в обозримом будущем. Например, в последний раз я не проверял ни одну версию компиляторов Microsoft, реализующих C99, и, насколько я понимаю, это все еще характерно для компиляторов встроенных систем, которые не являются GCC.
Показать ещё 3 комментария
0

Вот небольшая демонстрация использования кодов возврата...

При использовании различных инструментов, которые предоставляет терминал Linux, можно использовать код возврата, например, для обработки ошибок после завершения процесса. Представьте, что присутствует следующий файл myfile:

Вот пример, чтобы проверить, как работает grep.

При выполнении команды grep создается процесс. Как только он проходит (и не прерывается), он возвращает некоторый код между 0 и 255. Например:

$ grep order myfile

Если вы делаете

$ echo $?
$ 0

вы получите 0. Почему? Потому что grep нашел совпадение и вернул код выхода 0, что является обычным значением для выхода с успехом. Позвольте проверить это снова, но с чем-то, что не находится внутри нашего текстового файла, и поэтому совпадения не будет найдено:

$ grep foo myfile
$ echo $?
$ 1

Поскольку grep не смог сопоставить токен "foo" с содержимым нашего файла, код возврата равен 1 (это обычный случай, когда происходит сбой, но, как указано выше, у вас есть множество значений на выбор).

Теперь следующий bash script (просто введите его в терминале Linux), хотя очень базовый должен дать некоторое представление об обработке ошибок:

$ grep foo myfile
$ CHECK=$?
$ [ $CHECK -eq 0] && echo 'Match found'
$ [ $CHECK -ne 0] && echo 'No match was found'
$ No match was found

После второй строки ничего не печатается на терминале, так как "foo" сделал grep return 1, и мы проверяем, равен ли код возврата grep равным 0. Второй условный оператор перекликается с его сообщением в последней строке, так как он истинен из-за CHECK == 1.

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

  • 0
    В сценарии оболочки вы должны использовать if grep foo myfile; then echo 'Match found'; else echo 'No match was found'; fi - тестирование статуса возврата напрямую. Если вы хотите получить статус (для отчетов и т. Д.), Тогда вы используете назначение. Вы можете использовать, if grep foo myfile; CHECK=$?; [ "$CHECK" = 0 ]; then echo 'Match found'; else echo 'No match was found'; fi или вы могли бы использовать три строки. Вы также можете использовать опции -s и -q для grep чтобы предотвратить появление совпадений или обычных сообщений об ошибках. Однако, это мелочи оболочки - ключевой момент, что статус выхода может быть полезен - это нормально.
-1

void main() запрещено после C90. main должно возвращать значение. Я использовал для возврата 0.

-1

В основном это зависит от среды выполнения (ОС). C подразумевает, что он будет запускаться под UNIX-подобной ОС, которая ожидает, что программа вернет целое число (небольшое? 1 байт? Не может запомнить), чтобы указать успех/сбой.

Вероятно, вы должны просто использовать int main(int argc, char** argv).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню