Что должен вернуть main () в C и C++?

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


Есть множество дубликатов этого вопроса, в том числе:

Связанный:

Я все еще думаю, что это довольно расплывчато. Определите для меня «самый эффективный». В каком смысле эффективен? В смысле занимать меньше памяти? В смысле быстрее бегать? Я вижу полезные ответы, но все же думаю, что вопрос сформулирован довольно плохо.

Onorio Catenacci 16.10.2008 16:51

Pish posh, контекст эффективного здесь очевиден, особенно с примерами (которые, вероятно, там проясняют определение «эффективного»). Будем надеяться, что плохой буфер не залез в яму и полностью сожалею о своем вопросе. Можно сказать, что независимо от void или int возвращается значение, поэтому оно не влияет на размер файла, выполняемые операции или выделенную память. И люди в большинстве операционных систем, как правило, возвращают 0 в случае успеха и что-то еще в случае успеха или неудачи, но стандарта нет. В конечном счете, никакой очевидной разницы в эффективности.

Kit10 11.12.2012 21:02

«правильный (наиболее эффективный)» не имеет смысла. Эффективность - это одно, а правильность - другое. main вызывается один раз (а в C++ может вызываться только один раз: без рекурсии). Если вы не хотите, чтобы выполнение в main занимало много времени, не вызывайте программу много раз: пусть программа реализует повторение.

Kaz 17.10.2013 20:14

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

puk 12.11.2013 01:42

@puk: нет необходимости в «полностью рабочем примере», и для записи main() не нужны заголовки - даже если это будет необычная программа, для которой не нужны некоторые заголовки.

Jonathan Leffler 23.01.2014 20:39

То, что здесь до сих пор не упоминается ни в одном из ответов, заключается в том, что глава о типе возврата main, цитируемая повсюду, представляет собой подраздел из глава о размещенной среде, который, в свою очередь, является подраздел соответствующей главы Среда выполнения. Настоящие ответы на данный момент охватывают только 50% стандарта. Итак, я написал ответ, который нацелен на 100% ответ на вопрос.

Lundin 07.07.2015 11:09

Также по теме: Что послужило основанием для того, чтобы сделать return 0 в конце main необязательным?

Shafik Yaghmour 26.02.2017 11:50

Этот questin может быть расширен с помощью What is the Standard и порекомендовать способ использования main() в программах C.

EsmaeelE 28.10.2017 03:59

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

3Dave 26.06.2019 03:53
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
745
9
368 322
18
Перейти к ответу Данный вопрос помечен как решенный

Ответы 18

Ответ принят как подходящий

Возвращаемое значение 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;, остается открытым. Диапазон допустимых основных сигнатур программы C намного шире.

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

main МОЖНО вводить / выходить несколько раз, но эта программа, вероятно, не выиграет никаких дизайнерских наград;)

korona 15.10.2008 16:38

C99 также имеет неправильную функцию C++, заключающуюся в том, что достижение конца функции main () эквивалентно возврату 0 - если main () определен для возврата типа, совместимого с int (раздел 5.1.2.2.3).

Jonathan Leffler 15.10.2008 16:43

повторный вход в main не является допустимым C++. В стандарте 3.6.1.3 явно указано, что main не должен использоваться в программе.

workmad3 15.10.2008 16:59

stdlib.h предоставляет для этой цели EXIT_SUCCESS и EXIT_FAILURE

Clay 15.10.2008 17:13

@korona: использование main () изнутри кода - неопределенное поведение. Поскольку компилятор может (в зависимости от компилятора) вставить код для обработки инициализации программы на этом этапе. Дважды запускать код инициализации может быть не самой лучшей идеей.

Martin York 15.10.2008 20:07

0 и ненулевое значение верны, но совершенно бессмысленны для того, кто читает ваш код. Этот вопрос является доказательством того, что люди не знают, что такое действительные / недействительные коды. EXIT_SUCCESS / EXIT_FAILURE гораздо понятнее.

JaredPar 15.10.2008 20:32

JaredPar: возврат 0 из main четко определен в C как успешное завершение. Мартин Йорк: вызов main () изнутри программы на языке C, безусловно, является неопределенным поведением нет. Я не могу сказать то же самое о C++.

Chris Young 16.10.2008 13:28

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

workmad3 16.10.2008 17:25

Это может быть четко определено в стандарте C, но это определенно не совсем общеизвестно. В противном случае этот вопрос не был бы опубликован.

JaredPar 16.10.2008 21:26

JaredPar: ну, это общеизвестно среди программистов, которые знают C, и обычно я ожидаю, что люди, читающие исходный код C, поймут C.

Chris Young 19.10.2008 18:00

@ workmad3, обратите внимание на этот отчет о дефектах об использовании main для GCC: gcc.gnu.org/bugzilla/show_bug.cgi?id=41431. Также обратите внимание на следующие допустимые определения main: groups.google.com/group/comp.std.c++/browse_thread/thread/…

Johannes Schaub - litb 27.11.2009 19:08

Гарантируется ли, что возвращаемое значение основной функции будет кодом выхода из программы? Я всегда использовал функцию exit в своих программах, чтобы установить код выхода, отличный от 0.

Calmarius 27.05.2013 16:17

@ Калмарий: Да. Раздел 5.1.2.2.3 стандарта говорит: «... возврат из первоначального вызова функции main эквивалентен вызову функции exit со значением, возвращаемым функцией main в качестве аргумента ...»

Nemo 20.06.2013 05:39

Каждый разработчик на C знает, что код выхода INT 0 означает успех, так зачем же так много тонуть в стакане воды?

Frank R. 18.07.2013 11:14

Этот ответ охватывает только 50% стандартов, поскольку в нем не упоминаются автономные реализации. "void main () явно запрещена стандартом C++" ... необходима цитата (вы ее не найдете, она скорее неявно запрещает void main () для размещенных систем).

Lundin 07.07.2015 11:11

@Lundin main() упоминается только для размещенных форм C и C++. Таким образом, неявно вопрос касается размещенных C и C++.

Veltas 06.08.2015 22:35

Технически подпись должна быть unsigned char main(...), потому что подавляющее большинство сред оболочки требует, чтобы вы возвращали значение от 0 до 255.

Majora320 21.04.2016 05:18

@ Majora320: не совсем. Стандарты говорят int и означают int. Однако вы правы, что только 8 младших битов int используются в качестве статуса выхода. См. Также Коды выхода больше 255 - возможно?.

Jonathan Leffler 21.04.2016 05:56

'явно запрещен стандартом C++ и не должен использоваться' А также C. Даже если 'это работает', он сломан. Предположительно поэтому то же самое и в C++, если вы не имеете в виду, что он не будет компилироваться? Я не фанат C++, но в любом случае я знаю лучше, чем писать void main (), чтобы не столкнуться с проблемой.

Pryftan 22.02.2018 05:33

Вы забыли упомянуть int main(void); как действительную подпись в C. В C int main(); действительно означает int main(...). Только в C++ int main() означает int main(void). (Вот почему плохо, что вы говорили только о сигнатурах C++ для него)

Peter Cordes 13.04.2018 05:21

Ноль / ненулевое значение для сообщения об успехе / ошибке не соответствует действительности на всех платформах (например, VMS). В переносимом коде следует использовать макросы EXIT_SUCCESS / EXIT_FAILURE.

Jesper Juhl 12.06.2018 22:50

Дайте ссылку на "void main () явно запрещена стандартом C++", так как я не нахожу такого запрета в basic.start.main. Пока поддерживаются стандартные подписи, реализация может поддерживать любое количество нестандартных подписей. (Тем не менее, я бы сильно посоветовал бы не использовать такое расширение, даже если оно доступно).

Toby Speight 02.04.2019 11:38

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

Joshua 18.11.2020 01:49

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

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

@ChrisYoung Есть EXIT_SUCCESS и EXIT_FAILURE, потому что в некоторых старых операционных системах (VMS?) Для обозначения успеха использовалось число, отличное от 0. Сейчас везде 0.

fuz 17.09.2014 14:45

@FUZxxl, вы правы, но это не противоречит моему комментарию. EXIT_SUCCESS действительно может быть ненулевым, но все стандарты (C89, C99, C11) определяют 0 (а также EXIT_SUCCESS), чтобы также быть определяемой реализацией формой успешного завершения статуса.

Chris Young 22.10.2014 13:43

@ChrisYoung Спасибо, что поправили меня. Видимо, я ошибался.

fuz 22.10.2014 13:48

Хотя этот комментарий правильный и ценный, он не отвечает на вопрос.

Lundin 07.07.2015 11:15

@FUZxxl: это правда, что VMS использовала нечетные значения (например, 1) для обозначения успеха и четные значения (например, 0) для обозначения неудачи. К сожалению, исходный стандарт ANSI C интерпретировался как означающий, что EXIT_SUCCESS должен быть 0, поэтому возвращение EXIT_SUCCESS из main приводило к совершенно неправильному поведению в VMS. Портативным решением для VMS было использование exit(EXIT_SUCCESS), который всегда поступал правильно.

Adrian McCarthy 17.11.2016 03:19

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

Lundin 15.12.2017 16:38

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

Lundin 15.12.2017 16:38

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

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

C99 (и C++ 98) позволяют опускать оператор return из main; C89 не позволяет вам опускать оператор возврата.

Jonathan Leffler 18.07.2013 09:56

Это комментарий, а не ответ.

Lundin 07.07.2015 11:15

Это не дает ответа на вопрос. Чтобы критиковать или запрашивать разъяснения у автора, оставьте комментарий под его сообщением.

Steve Lillis 07.07.2015 12:15

@SteveLillis: В 2008 году у SO не было раздела для комментариев.

graham.reeds 07.07.2015 14:08

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

Unix делает то же самое, вероятно, и большинство других операционных систем. Я знаю, что VMS делает с ним такие невероятные странные вещи, что возвращение чего-либо, кроме EXIT_SUCCESS или EXIT_FAILURE, вызывает проблемы.

Leon Timmermans 16.10.2008 20:34

MSDN требует отличия: когда сообщается через mscorlib, код выхода - 32-битное целое число со знаком. Похоже, это означает, что Библиотеки времени выполнения C, который усекает коды выхода, неисправен.

user824425 05.01.2015 13:16

Да, это неверно. В Windows возвращается 32-битное целое число (и преобразуется в unsigned). То же самое в системах UNIX с 32-битными целыми числами. Но оболочки в стиле UNIX в любой системе обычно сохраняют только 8-битное целое число без знака.

John McFarlane 29.07.2017 23:58

Принятый ответ, похоже, предназначен для C++, поэтому я подумал, что добавлю ответ, относящийся к C, и это несколько отличается. Также были внесены некоторые изменения между ISO / IEC 9899: 1989 (C90) и ISO / IEC 9899: 1999 (C99).

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

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

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

Если реализация позволяет это, main() может быть объявлен другими способами (например, int main(int argc, char *argv[], char *envp[])), но это делает реализацию программы определенной и больше не соответствует строго.

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

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

@ Крис Янг: Куда денется возвращаемое значение. И какой толк от возвращенного значения? Вы можете это объяснить. или просто чтобы избежать неопределенного поведения.

MELWIN 07.03.2014 15:51

@ MELWIN: возвращаемое значение передается в среду хоста. В большинстве случаев это будет ваша ОС, которая может передать это значение другому запущенному процессу по запросу (например, вызову system ()).

Ternvein 09.01.2015 14:02

Что касается «Стандарт определяет 3 значения для возврата ... 0, EXIT_SUCCESS, EXIT_FAILURE», действительно ли «0, EXIT_SUCCESS, EXIT_FAILURE» является частью спецификаций ISO-C и C++? Если да, то где в спецификациях?

Trevor Boyd Smith 15.05.2015 17:27

C11 §7.22p3 и §7.22.4.4p5. C++ 11 ссылается на стандартную библиотеку C, но они кратко упомянуты в §18.5p3.

Chris Young 17.05.2015 14:40

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

Lundin 07.07.2015 11:17

@Lundin Я не думаю, что вам нужна цитата, чтобы сказать, что кому-то разрешено создавать компилятор, который принимает нестандартные программы, или иметь компилятор, не соответствующий стандартам. Это общеизвестно и здравый смысл

KABoissonneault 07.07.2015 17:44

@KABoissonneault Поведение, определяемое реализацией, - это термин из стандарта, в отличие от полностью недокументированного поведения. Если вы реализуете что-то, что указано как поведение, определяемое реализацией, вы по-прежнему следуете стандарту. В этом случае C89, который был процитирован, не перечисляет такое поведение, определяемое реализацией, поэтому необходимо цитировать, чтобы доказать, что он не просто выдумывает что-то на ровном месте.

Lundin 08.07.2015 10:00

@Lundin Ты неправильно понимаешь. То, о чем мы говорим, не является поведением, определяемым реализацией, мы говорим о реализации, отклоняющейся от стандарта, если они того пожелают. Это больше похоже на то, как ребенок не слушается своих родителей: вам не нужна цитата из родителей, чтобы сказать вам, каким образом ребенок может пойти против того, что говорят родители. Вы просто знаете, что в тот момент, когда ребенок решает это сделать, он больше не соблюдает гильдена своих родителей.

KABoissonneault 08.07.2015 15:07

@KABoissonneault Часть, которую я процитировал в своем комментарии, определенно касается поведения, определяемого реализацией (в отличие от нестандартные расширения компилятора). Таким образом, я говорю о поведении, определяемом реализацией. Если у вас есть монолог о другом, удачи вам с этим.

Lundin 08.07.2015 15:33

@Lundin Я полагаю, что формулировка в цитате сбивает с толку (часть, где говорится «но это определяет реализацию программы»), но я почти уверен, что этот человек говорил о нестандартном поведении (как сказано в «Если выполнение разрешает это «и» и больше не соответствует [стандарту] ») в отличие от поведения, определяемого реальной реализацией. Человеку обязательно стоит перефразировать свой ответ, но я все же не думаю, что для этого нужна цитата из стандарта.

KABoissonneault 08.07.2015 15:39

«но это делает реализацию программы определенной, а не строгим соответствием». -> Код все еще соответствует. Конечно, менее вероятно с сигнатурой, определенной реализацией.

chux - Reinstate Monica 01.12.2017 19:33
main () должен иметь явный оператор возврата в конце, чтобы избежать неопределенного поведения. : only holds for non-main functions. The C standard explicitly allows not to put the return statement for the main function, and states that in such a case a return 0 will be automatically generated by the compiler. No UB is triggered in this case. Please see answers below for quotations from the standard.
programmersn 21.06.2019 20:33

@programmersn часть, которую вы цитируете в моем ответе, касается C90. Если вы продолжите читать часть ниже (C99), вы увидите, что я говорю, что вы можете опустить возврат из main (), поскольку есть неявный возврат 0. Это потому, что это было добавлено в стандарт только с C99.

Chris Young 23.06.2019 05:59

@Chris: Плохо, что я не увидел этой части ответа, сразу сделал вывод. Не могли бы вы внести какие-либо изменения в ответ, чтобы я мог отозвать отрицательный голос. В любом случае спасибо за разъяснения

programmersn 24.06.2019 15:51

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

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

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

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

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

Lundin 15.12.2017 16:42

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

phoxis 18.12.2017 22:32

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

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

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

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

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

Lundin 07.07.2015 11:18

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

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

Lundin 07.07.2015 11:18

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, чтобы узнать, что произошло с вашей программой, и контролировать весь поток.

Строго говоря, $? не является переменной среды; это предопределенная (или встроенная) переменная оболочки. Разницу трудно заметить, но если вы запустите env (без аргументов), он распечатает среду, и $? не будет отображаться в среде.

Jonathan Leffler 23.09.2013 03:20

Автоматическое возвращение 0, когда основное "падает до конца" только в C++ и C99 и далее, а не в C90.

Kaz 17.10.2013 20:43

Опечатка: «закрытие {» должно быть }. ТАК не позволит мне сделать такое маленькое редактирование.

Spencer 25.03.2020 20:12

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

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

Jonathan Leffler 23.09.2013 03:17

@JonathanLeffler: Значение возврата 1 из main определяется реализацией. Единственными языковыми значениями являются 0, EXIT_SUCCESS (часто обозначаемый как 0) и EXIT_FAILURE. В OpenVMS return 1; обозначает завершение успешный.

Keith Thompson 06.02.2014 01:59

VMS не «нормальный» - в смысле того, что я сказал. Разве это не что-то вроде «любая нечетная ценность - успех; даже значения сбой на VMS?

Jonathan Leffler 06.02.2014 02:02

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

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

5.1.2.2.1 Program startup

The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:

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

or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):

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

or equivalent;10) or in some other implementation-defined manner.

If they are declared, the parameters to the main function shall obey the following constraints:

  • The value of argc shall be nonnegative.
  • argv[argc] shall be a null pointer.
  • If the value of argc is greater than zero, the array members argv[0] through argv[argc-1] inclusive shall contain pointers to strings, which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment. If the host environment is not capable of supplying strings with letters in both uppercase and lowercase, the implementation shall ensure that the strings are received in lowercase.
  • If the value of argc is greater than zero, the string pointed to by argv[0] represents the program name; argv[0][0] shall be the null character if the program name is not available from the host environment. If the value of argc is greater than one, the strings pointed to by argv[1] through argv[argc-1] represent the program parameters.
  • The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.

10) Thus, int can be replaced by a typedef name defined as int, or the type of argv can be written as char **argv, and so on.

Завершение программы в C99 или C11

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

5.1.2.2.3 Program termination

1 If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument;11) reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspecified.

11) In accordance with 6.2.4, the lifetimes of objects with automatic storage duration declared in main will have ended in the former case, even where they would not have in the latter.

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

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

7.22.4.4 The exit function

¶5 Finally, control is returned to the host environment. If the value of status is zero or EXIT_SUCCESS, an implementation-defined form of the status successful termination is returned. If the value of status is EXIT_FAILURE, an implementation-defined form of the status unsuccessful termination is returned. Otherwise the status returned is implementation-defined.

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

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

3.6.1 Main function [basic.start.main]

¶1 A program shall contain a global function called main, which is the designated start of the program. [...]

¶2 An implementation shall not predefine the main function. This function shall not be overloaded. It shall have a return type of type int, but otherwise its type is implementation defined. All implementations shall allow both of the following definitions of main:

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

and

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

In the latter form argc shall be the number of arguments passed to the program from the environment in which the program is run. If argc is nonzero these arguments shall be supplied in argv[0] through argv[argc-1] as pointers to the initial characters of null-terminated multibyte strings (NTMBSs) (17.5.2.1.4.2) and argv[0] shall be the pointer to the initial character of a NTMBS that represents the name used to invoke the program or "". The value of argc shall be non-negative. The value of argv[argc] shall be 0. [ Note: It is recommended that any further (optional) parameters be added after argv. —end note ]

¶3 The function main shall not be used within a program. The linkage (3.5) of main is implementation-defined. [...]

¶5 A return statement in main has the effect of leaving the main function (destroying any objects with automatic storage duration) and calling std::exit with the return value as the argument. If control reaches the end of main without encountering a return statement, the effect is that of executing

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 тем, что у нее нет заголовка, который ее объявляет.

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

J.5.1 Environment arguments

¶1 In a hosted environment, the main function receives a third argument, char *envp[], that points to a null-terminated array of pointers to char, each of which points to a string that provides information about the environment for this execution of the program (5.1.2.2.1).

Microsoft C

Компилятор Microsoft VS 2010 интересен. На сайте написано:

The declaration syntax for main is

 int main();

or, optionally,

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

Alternatively, the main and wmain functions can be declared as returning void (no return value). If you declare main or wmain as returning void, you cannot return an exit code to the parent process or operating system by using a return statement. To return an exit code when main or wmain is declared as void, you must use the exit function.

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

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

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

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

Стандарт C - Отдельностоящая среда

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

5.1.2 Execution environments

Two execution environments are defined: freestanding and hosted. In both cases, program startup occurs when a designated C function is called by the execution environment. All objects with static storage duration shall be initialized (set to their initial values) before program startup. The manner and timing of such initialization are otherwise unspecified. Program termination returns control to the execution environment.

5.1.2.1 Freestanding environment

In a freestanding environment (in which C program execution may take place without any benefit of an operating system), the name and type of the function called at program startup are implementation-defined. Any library facilities available to a freestanding program, other than the minimal set required by clause 4, are implementation-defined.

The effect of program termination in a freestanding environment is implementation-defined.

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

¶5 A strictly conforming program shall use only those features of the language and library specified in this International Standard.3) It shall not produce output dependent on any unspecified, undefined, or implementation-defined behavior, and shall not exceed any minimum implementation limit.

¶6 The two forms of conforming implementation are hosted and freestanding. A conforming hosted implementation shall accept any strictly conforming program. A conforming freestanding implementation shall accept any strictly conforming program in which the use of the features specified in the library clause (clause 7) is confined to the contents of the standard headers <float.h>, <iso646.h>, <limits.h>, <stdalign.h>, <stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h>, and <stdnoreturn.h>. A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any strictly conforming program.4)

¶7 A conforming program is one that is acceptable to a conforming implementation.5)

3) A strictly conforming program can use conditional features (see 6.10.8.3) provided the use is guarded by an appropriate conditional inclusion preprocessing directive using the related macro. For example:

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

4) This implies that a conforming implementation reserves no identifiers other than those explicitly reserved in this International Standard.

5) Strictly conforming programs are intended to be maximally portable among conforming implementations. Conforming programs may depend upon non-portable features of a conforming implementation.

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

Стандартный C++ - Автономная среда

Так же, как стандарт C распознает как размещенную, так и автономную среду, стандарт C++ тоже. (Цитаты из ISO / IEC 14882: 2011.)

1.4 Implementation compliance [intro.compliance]

¶7 Two kinds of implementations are defined: a hosted implementation and a freestanding implementation. For a hosted implementation, this International Standard defines the set of available libraries. A freestanding implementation is one in which execution may take place without the benefit of an operating system, and has an implementation-defined set of libraries that includes certain language-support libraries (17.6.1.3).

¶8 A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any well-formed program. Implementations are required to diagnose programs that use such extensions that are ill-formed according to this International Standard. Having done so, however, they can compile and execute such programs.

¶9 Each implementation shall include documentation that identifies all conditionally-supported constructs that it does not support and defines all locale-specific characteristics.3

3) This documentation also defines implementation-defined behavior; see 1.9.

17.6.1.3 Freestanding implementations [compliance]

Two kinds of implementations are defined: hosted and freestanding (1.4). For a hosted implementation, this International Standard describes the set of available headers.

A freestanding implementation has an implementation-defined set of headers. This set shall include at least the headers shown in Table 16.

The supplied version of the header <cstdlib> shall declare at least the functions abort, atexit, at_quick_exit, exit, and quick_exit (18.5). The other headers listed in this table shall meet the same requirements as for a hosted implementation.

Table 16 — C++ headers for freestanding implementations

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 The sizeof and _Alignof operators

¶8 EXAMPLE 3 In this example, the size of a variable length array is computed and returned from a function:

#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;
}

@DavidBowling: определение функции вроде int main(){ … } указывает, что функция не принимает аргументов, но не предоставляет прототип функции AFAICT. Для main() это редко бывает проблемой; это означает, что если у вас есть рекурсивные вызовы main(), аргументы не будут проверяться. Для других функций это больше проблема - вам действительно нужен прототип в области видимости, когда функция вызывается, чтобы гарантировать правильность аргументов.

Jonathan Leffler 13.12.2017 18:58

@DavidBowling: Обычно вы не вызываете main() рекурсивно за пределами таких мест, как IOCCC. У меня есть тестовая программа, которая это делает - в основном для новинок. Если у вас есть int i = 0; int main() { if (i++ < 10) main(i, i * i); return 0; }, и вы компилируете с GCC и не включаете -Wstrict-prototypes, он компилируется без ошибок при строгих предупреждениях. Если это main(void), он не компилируется.

Jonathan Leffler 13.12.2017 19:42

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

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

This is some example in order to check how grep works.

Когда вы выполняете команду 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 ()).

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

Jonathan Leffler 16.02.2019 21:54

Обратите внимание, что стандарты C и 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

Разрешена любая форма или название основного 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 main4.

Тем не менее, в разделе о завершении программы в размещенной среде продолжаются споры о случае, когда 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 Function declarators

The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.


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

Допустимые формы 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 Размещенная среда. «Запуск программы»

The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:

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

or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):

    int main(int argc, char *argv[]) { /* ... */ }
  1. ANSI X3.159-1989 2.1.2.1 Автономная среда:

In a freestanding environment (in which C program execution may take place without any benefit of an operating system), the name and type of the function called at program startup are implementation-defined.

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

The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:

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

or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):

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

or equivalent;9) or in some other implementation-defined manner.

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

The behavior of the arguments to main, and of the interaction of exit, main and atexit (see §7.20.4.2) has been codified to curb some unwanted variety in the representation of argv strings, and in the meaning of values returned by main.

The specification of argc and argv as arguments to main recognizes extensive prior practice. argv[argc] is required to be a null pointer to provide a redundant check for the end of the list, also on the basis of common practice.

main is the only function that may portably be declared either with zero or two arguments. (The number of other functions’ arguments must match exactly between invocation and definition.) This special case simply recognizes the widespread practice of leaving off the arguments to main when the program does not access the program argument strings. While many implementations support more than two arguments to main, such practice is neither blessed nor forbidden by the Standard; a program that defines main with three arguments is not strictly conforming (see §J.5.1.).

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

If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument;11) reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspecified.

  1. ISO 9899: 1999 5.1.2.1 Автономная среда

In a freestanding environment (in which C program execution may take place without any benefit of an operating system), the name and type of the function called at program startup are implementation-defined.

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

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

  1. ISO 9899: 1999 5.1.2.1 Автономная среда

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

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

An implementation shall not predefine the main function. This function shall not be overloaded. It shall have a return type of type int, but otherwise its type is implementation-defined. All implementations shall allow both of the following definitions of main:

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

and

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

It is implementation-defined whether a program in a freestanding environment is required to define a main function.

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

An implementation shall not predefine the main function. This function shall not be overloaded. It shall have a return type of type int, but otherwise its type is implementation-defined. All implementations shall allow both

— a function of () returning int and

— a function of (int, pointer to pointer to char) returning int

as the type of main (8.3.5).

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

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

Один вопрос: означают ли стандарты C++, что сигнатура функции запуска в автономных средах также определяется реализацией? Например, реализация могла бы определить функцию запуска как int my_startup_function () или int my_startup_function (int argc, char *argv[]), но может ли она иметь, например, char my_startup_function (long argc, int *argv[]) как функцию запуска? Думаю, нет, правда? Кроме того, разве это не неоднозначно?

Utku 17.11.2015 13:55

@Utku Он может иметь любую подпись, если он не называется main(), потому что тогда он должен использовать одну из перечисленных подписей. Я бы предположил, что наиболее распространенным будет void my_startup_function (), поскольку нет смысла возвращаться из программы в автономных системах.

Lundin 17.11.2015 14:07

Понятно. Но если разрешено использовать любое имя и любую подпись для функции запуска, почему бы не разрешить использовать другую подпись и для main? Извините, если это не умный вопрос, но я не мог понять причину.

Utku 17.11.2015 14:18

@Utku C и C++ там разные. Что касается того, почему C++ обеспечивает это, я понятия не имею, нет никакого объяснения. Я подозреваю, что главный виновник (каламбур) - это Страуструп, который на раннем этапе заявил, что main должен возвращать int, период. Потому что, когда он сделал первую версию C++, он использовался только для хостинговых систем. В связанном сообщении Страуструп по-прежнему, кажется, не обращает внимания на существование автономных реализаций: например, он по незнанию ссылается на подглаву размещенной реализации стандарта C, игнорируя существование главы 5.1.2.1.

Lundin 17.11.2015 15:09

Примечательно, что черновик стандарта C11 состоит в том, что, хотя func() считается устаревшим, сам проект использует int main() в своих собственных примерах.

Antti Haapala 13.03.2016 13:48

Что случилось с подписью с тремя аргументами int main(int argc, char **argv, char **envp);

Spencer 25.03.2020 20:10

@Spencer Это никогда не было стандартным. Он упоминается среди «общих расширений» в стандартном Приложении J.5.

Lundin 26.03.2020 10:07

Опустить return 0

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

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

[...] a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the main function returns a value of 0.

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

If control reaches the end of main without encountering a return statement, the effect is that of executing return 0;

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

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

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

Примечание: The purpose for this answer is to allow those of us frequently giving this advice on CodeReview a StackOverflow answer to which we can point to regarding the practice of omitting return 0;
Edward 24.04.2017 15:02

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

zwol 13.05.2017 20:09

@zwol: у любого, у кого нет выбора, кроме как использовать компилятор, который устарел на 28 лет, вероятно, будет больше проблем, чем решить, включать ли явно return 0;, однако я бы отметил, что многие компиляторы той эпохи также реализовали неявный return 0; даже раньше. он был стандартизирован.

Edward 13.05.2017 20:15

То, что вы говорите, правда. Я хочу только дать объяснение реакции «плохой совет», которая не просто «выглядит странно».

zwol 13.05.2017 20:17

На самом деле, я много работаю со встроенными системами и более десяти лет не встречал компилятора, который не поддерживает неявный return 0. Также текущие версии Microsoft C также поддерживай это. Возможно, ваша информация устарела?

Edward 13.05.2017 20:27

Я могу оценить это является спорным в C, почти (за @zwol). В C++ любые споры вокруг этого - полная чушь.

Lightness Races in Orbit 09.06.2019 17:54

@LightnessRacesinOrbit Вы могли бы так поступить, но ... codereview.stackexchange.com/questions/221922/c-logging-libr‌ ary /…

Edward 09.06.2019 18:04

@ Эдвард Я не говорил, что спор не существует, я сказал, что это ерунда: P

Lightness Races in Orbit 09.06.2019 18:05

What is the correct (most efficient) way to define the main() function in C and C++ — int main() or void main() — and why?

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

What should main() return in C and C++?

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

If int main() then return 1 or return 0?

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

В C Раздел 5.1.2.2.1 стандарта C11 (выделено мной):

It shall be defined with a return type of int and with no parameters:

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

or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):

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

Однако для некоторых новичков, таких как я, абстрактный пример позволил бы мне понять это:

Когда вы пишете метод в своей программе, например int read_file(char filename[LEN]);, тогда вы, как вызывающий этот метод, хотите знать, все ли прошло хорошо (потому что могут произойти сбои, например, файл не может быть найден). Проверяя возвращаемое значение метода, вы можете узнать, все ли прошло хорошо или нет, это механизм для метода, который сигнализирует вам об успешном выполнении (или нет), и позволяет вызывающему (например, в вашем основном методе) решать как справиться с неожиданной ошибкой.

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

Другими словами:

Рациональным является то, что среда хоста (то есть операционная система (ОС)) должна знать, правильно ли завершилась программа. Без int-совместимого типа в качестве возвращаемого типа (например, void) «статус, возвращаемый в среду хоста, не указан» (т.е. неопределенное поведение в большинстве ОС).

Другие вопросы по теме