it-swarm.com.ru

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

640
Joel

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

int main()

а также

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

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

int main(int argc, char** argv)

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

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

528
workmad3

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

ИСО/МЭК 9899: 1989 (С90):

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 в конце, чтобы избежать неопределенного поведения.

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

ISO/IEC 9899: 1999 (C99):

Для C99 все то же самое, что и выше, за исключением:

  • Возвращаемый тип int не может быть опущен.
  • Вы можете опустить оператор возврата из main(). Если вы это сделаете, и main() завершится, то будет скрытый return 0.
156
Chris

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

Для размещенной среды (это нормальная среда) стандарт 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] включительно должны содержать указатели на строки, которым перед установкой программы присваиваются значения, определяемые реализацией средой Host. Намерение состоит в том, чтобы предоставить программе информацию, определенную до ее запуска, из другого места в размещенной среде. Если среда хоста не может предоставлять строки с буквами как в верхнем, так и в нижнем регистре, реализация должна обеспечивать получение строк в нижнем регистре.
  • Если значение 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() вернется, но не определит возвращаемое значение; следовательно, это ведет к неопределенному поведению.

7.22.4.4 Функция exit

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

Стандарт C++ - Хостинг-среда

Стандарт C++ 11 (ISO/IEC 14882: 2011) гласит:

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

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

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

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

а также

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

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

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

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

return 0;

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

В стандарте 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 Аргументы среды

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

Microsoft C

Компилятор Microsoft VS 201 интересен. Веб-сайт говорит:

Синтаксис объявления для 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 и C++. Он только предписывает форму с тремя аргументами, где третьим аргументом является char **envp, указатель на список переменных среды.

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

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

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

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

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

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

5.1.2.1 Отдельно стоящая среда

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

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

Перекрестная ссылка на пункт 4 Соответствие относится к этому:

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

¶6 Двумя формами соответствующей реализации являются hosted и отдельно стоящие . Соответствующая размещенная реализация должна принимать любую строго соответствующую программу. Соответствующая автономная реализация должна принимать любую строго соответствующую программу, в которой использование функций, указанных в разделе библиотеки (пункт 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++ - автономная среда

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

1.4 Соответствие реализации [intro.compliance]

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

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

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

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

17.6.1.3 Отдельно стоящие реализации [соответствие]

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

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

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

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

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 )2 . Теперь важно отметить, что примеры не являются "нормативными"; они только иллюстративны. Если в примерах есть ошибки, они не влияют напрямую на основной текст стандарта. Тем не менее, они строго указывают на ожидаемое поведение, поэтому, если стандарт включает в себя int main() в примере, он предполагает, что int main() не запрещена, даже если это не предпочтительная нотация.

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

...

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

#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;
}
110
Jonathan Leffler

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

58
dmityugov

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

  • среда размещения C9

    Разрешенные формы 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 автономная среда

    Разрешается любая форма или имя главного 2,.

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

    Разрешенные формы 3:

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

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

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

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

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

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

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

  • автономная среда C99

    Разрешается любая форма или имя главного 6,.

  • среда размещения C11

    Разрешенные формы 7:

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

    Разрешается любая форма или имя главного 8,.


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

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

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


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

    Разрешенные формы 9:

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

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

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

  • C++ 03 автономная среда

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

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

    Разрешенные формы 11:

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

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

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

  • автономная среда C++ 11

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

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

ссылки

  1. ANSI X3.159-1989 2.1.2.2 Размещенная среда. "Запуск программы"

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

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

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

    int main(int argc, char *argv[]) { /* ... */ }
    
  2. ANSI X3.159-1989 2.1.2.1 Отдельно стоящая среда:

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

  3. ISO 9899: 1999 5.1.2.2 Размещенная среда -> 5.1.2.2.1 Запуск программы

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

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

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

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

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

  4. Обоснование международного стандарта - языки программирования - C, редакция 5.10. 5.1.2.2 Размещенная среда -> 5.1.2.2.1 Запуск программы

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

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

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

  5. ISO 9899: 1999 5.1.2.2 Размещенная среда -> 5.1.2.2.3 Завершение программы

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

  6. ISO 9899: 1999 5.1.2.1 Отдельно стоящая среда

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

  7. ISO 9899: 2011 5.1.2.2 Размещенная среда -> 5.1.2.2.1 Запуск программы

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

  8. ISO 9899: 1999 5.1.2.1 Отдельно стоящая среда

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

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

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

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

    а также

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

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

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

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

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

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

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

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

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

38
Lundin

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

28
Lou Franco

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

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

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

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

$ ./a.out
$ echo $?

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

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

8
Jeegar Patel

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

7
Ferruccio

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

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

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

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

4
Yochai Timmer

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

3
Fahad Uddin

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

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

2
graham.reeds

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

2
Vamsi Pavan Mahesh

Пропустить return 0

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

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

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

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

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

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

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

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

1
Edward

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

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

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

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

Если int main (), тогда вернуть 1 или вернуть 0?

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

1
Steve Summit

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

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

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

1
Luca C.

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

1
phoxis

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

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

Это пример того, как проверить, как работает grep.

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

$ grep order myfile

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

$ echo $?
$ 0

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

$ grep foo myfile
$ echo $?
$ 1

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

Теперь следующий скрипт bash (просто введите его в терминале 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 возвращать 1, и мы проверяем, был ли код возврата grep равен 0. Второе условное выражение повторяет свое сообщение в последней строке, так как оно истинно из-за CHECK == 1.

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

0
rbaleksandar