Как правильно (наиболее эффективно) определить main()
функцию в C и C ++ - int main()
или void main()
- и почему? Если int main()
тогда return 1
или return 0
?
Существует множество дубликатов этого вопроса, в том числе:
- Каковы действительные подписи для
main()
функции C ? - Возвращаемый тип
main()
функции - Разница между
void main()
аint main()
? main()
подпись в C ++- Что такое правильная декларация
main()
? - Для C ++, с очень хорошим ответом. - Стили
main()
функций в Си - Тип возврата
main()
метода в C int main()
противvoid main()
C
Связанные с:
- C ++ -
int main(int argc, char **argv)
- C ++ -
int main(int argc, char *argv[])
- Является ли
char *envp[]
третьим аргументом в пользуmain()
портативного? - Должна ли
int main()
функция возвращать значение во всех компиляторах? - Почему тип
main()
функции в C и C ++ оставлен на усмотрение пользователя? - Почему
int main(){}
компилируется? - Юридические определения
main()
в C ++ 14?
c++
c
return-value
main
return-type
Joel
источник
источник
main
вызывается один раз (а в C ++ может вызываться только один раз: без рекурсии). Если вы не хотите, чтобы выполнение затрачивало много времениmain
, не запускайте программу большое количество раз: заставьте программу реализовать повторение.#include
высказыванияreturn
вmain(...)
на встроенном устройстве, система переходит в непредсказуемом состоянии и ваша стиральная машина будет самосознанием и попытаться убить вас. Итак, мы используемvoid main()
в этом случае. Это стандартная отраслевая практика в области применения голого металла.Ответы:
Возвращаемое значение для
main
указывает, как программа вышла. Нормальный выход представлен 0 возвращаемым значением изmain
. Ненормальный выход сигнализируется ненулевым возвратом, но не существует стандарта для интерпретации ненулевых кодов. Как отмечают другие,void main()
это запрещено стандартом C ++ и не должно использоваться. Допустимыеmain
подписи C ++ :а также
что эквивалентно
Стоит также отметить, что в C ++
int main()
можно оставить без оператора return, после чего по умолчанию возвращается 0. Это также верно для программы C99.return 0;
Должен ли он быть опущен или нет, открыт для обсуждения. Диапазон действительных основных сигнатур программы на Си намного больше.Эффективность не проблема с
main
функцией. Он может быть введен и оставлен только один раз (отмечен запуск и завершение программы) в соответствии со стандартом C ++. Для C повторный вводmain()
разрешен, но его следует избегать.источник
Принятый ответ, по-видимому, предназначен для C ++, поэтому я подумал, что добавлю ответ, относящийся к C, и он отличается в нескольких отношениях.
ИСО / МЭК 9899: 1989 (С90):
main()
должен быть объявлен как:Или эквивалент. Например,
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
.источник
Стандарт С - размещенная среда
Для размещенной среды (это нормальная среда) стандарт C11 (ISO / IEC 9899: 2011) гласит:
Завершение программы в C99 или C11
Возвращаемое значение
main()
передается в «среду» способом, определяемым реализацией.Обратите внимание, что
0
указано как «успех». Вы можете использоватьEXIT_FAILURE
иEXIT_SUCCESS
из,<stdlib.h>
если вы предпочитаете, но 0 хорошо установлено, и так же 1. См. Также Коды выхода больше 255 - возможно? ,В C89 (и, следовательно, в Microsoft C) нет заявления о том, что произойдет, если
main()
функция вернется, но не определит возвращаемое значение; следовательно, это ведет к неопределенному поведению.Стандарт C ++ - Хостинг-среда
Стандарт C ++ 11 (ISO / IEC 14882: 2011) гласит:
Стандарт C ++ явно говорит: «Он [основная функция] должен иметь тип возвращаемого типа
int
, но в противном случае его тип определяется реализацией», и для поддержки в качестве опций требуются те же две подписи, что и для стандарта C. Таким образом, void main () напрямую не разрешен стандартом C ++, хотя он ничего не может сделать, чтобы остановить нестандартную реализацию, допускающую альтернативы. Обратите внимание, что C ++ запрещает пользователю звонитьmain
(но стандарт C этого не делает).Там в пункте §18.5 Начало и окончание в C ++ 11 стандарт , который идентичен пункту из §7.22.4.4 функции в стандарте C11 (процитированном выше), за исключением сноски (который просто документы, и определяются в )
exit
EXIT_SUCCESS
EXIT_FAILURE
<cstdlib>
Стандарт C - Общее расширение
Классически системы Unix поддерживают третий вариант:
Третий аргумент представляет собой список указателей на строки с нулевым символом в конце, каждый из которых представляет собой переменную окружения, которая имеет имя, знак равенства и значение (возможно, пустое). Если вы не используете это, вы все равно можете попасть в среду через '
extern char **environ;
'. Эта глобальная переменная уникальна среди тех, что в POSIX, потому что у нее нет заголовка, который ее объявляет.Это признано стандартом C как общее расширение, документированное в Приложении J:
Microsoft C
Microsoft VS 2010 компилятор интересно. Веб-сайт говорит:
Мне не ясно, что происходит (какой код выхода возвращается родительскому или ОС), когда программа с ним
void main()
завершает работу - и веб-сайт MS тоже молчит.Интересно, что MS не предписывает версию с двумя аргументами,
main()
которая требуется для стандартов C и C ++. Он только предписывает форму с тремя аргументами, где третий аргумент -char **envp
указатель на список переменных среды.На странице Microsoft также перечислены некоторые другие альтернативы,
wmain()
которые принимают строки широких символов, и некоторые другие.Версия этой страницы для Microsoft Visual Studio 2005 не указана в качестве альтернативы. В версии от Microsoft Visual Studio 2008 года сделать.
void main()
Стандарт С - автономная среда
Как уже отмечалось ранее, вышеуказанные требования применяются к размещенным средам. Если вы работаете с автономной средой (которая является альтернативой размещенной среде), то о стандарте можно сказать гораздо меньше. В автономной среде нет необходимости вызывать функцию, вызываемую при запуске программы,
main
и нет ограничений на тип возвращаемого значения. Стандарт гласит:Перекрестная ссылка на пункт 4 Соответствие относится к этому:
Заметно, что единственный отдельный заголовок, необходимый для автономной среды, которая фактически определяет какие-либо функции, - это
<stdarg.h>
(и даже они могут быть - и часто это - просто макросы).Стандарт C ++ - автономная среда
Так же, как стандарт C признает как размещенную, так и автономную среду, то же самое относится и к стандарту C ++. (Цитаты из ИСО / МЭК 14882: 2011.)
Как насчет использования
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()
это не запрещено, даже если это не является предпочтительным обозначением.источник
int main(){ … }
, которое указывает, что функция не принимает аргументов, но не предоставляет прототип функции AFAICT. Ибоmain()
это редко проблема; это означает, что если у вас есть рекурсивные вызовыmain()
, аргументы не будут проверены. Для других функций это большая проблема - вам действительно нужен прототип в области видимости, когда функция вызывается, чтобы убедиться, что аргументы верны.main()
рекурсивно, за пределами таких мест, как IOCCC. У меня есть тестовая программа, которая делает это - главным образом для новизны. Если у вас естьint i = 0; int main() { if (i++ < 10) main(i, i * i); return 0; }
и скомпилируйте с GCC и не включайте-Wstrict-prototypes
, он компилируется чисто под строгие предупреждения. Если этоmain(void)
, это не в состоянии скомпилировать.Я считаю , что
main()
должен возвращать либоEXIT_SUCCESS
илиEXIT_FAILURE
. Они определены вstdlib.h
источник
EXIT_SUCCESS
иEXIT_FAILURE
потому, что некоторые исторические операционные системы (VMS?) Использовали номер, отличный от 0, для обозначения успеха. Сейчас 0 везде.exit(EXIT_SUCCESS)
, которое всегда делало правильные вещи.Обратите внимание, что стандарты C и C ++ определяют два вида реализаций: автономные и размещенные.
C90 размещенная среда
Разрешенные формы 1 :
Комментарии:
Первые два явно указаны как разрешенные формы, остальные неявно разрешены, потому что C90 допускает «неявное int» для возвращаемого типа и параметров функции. Никакая другая форма не допускается.
C90 автономная среда
Разрешается любая форма или имя главного 2 .
C99 размещенная среда
Разрешенные формы 3 :
Комментарии:
C99 удалил "implicit int", поэтому
main()
больше не действителен.Было введено странное, неоднозначное предложение «или каким-то другим образом, определяемым реализацией». Это может быть либо интерпретировано как «параметры
int main()
могут различаться», либо как «main может иметь любую форму, определяемую реализацией».Некоторые компиляторы решили интерпретировать стандарт последним способом. Можно утверждать, что нелегко утверждать, что они не совсем соответствуют, цитируя стандарт сам по себе, поскольку он неоднозначен.
Однако разрешить совершенно дикие формы,
main()
вероятно, (?) Не было целью этого нового предложения. Обоснование C99 (не нормативное) подразумевает, что предложение относится к дополнительным параметрам кint main
4 .Тем не менее, раздел для завершения программы размещенной среды продолжает спорить о случае, когда main не возвращает int 5 . Хотя этот раздел не является нормативным для того, как main должен быть объявлен, он определенно подразумевает, что main может быть объявлен полностью определяемым реализацией способом даже в размещенных системах.
C99 автономная среда
Разрешается любая форма или имя главного 6 .
С11 размещенная среда
Разрешенные формы 7 :
C11 автономная среда
Разрешается любая форма или имя главного лица 8 .
Обратите внимание, что
int main()
никогда не был указан в качестве допустимой формы для любой размещенной реализации C в любой из вышеуказанных версий. В C, в отличие от C ++,()
и(void)
имеют разные значения. Первый является устаревшей функцией, которая может быть удалена из языка. Смотрите C11 будущие языковые направления:C ++ 03 размещенная среда
Разрешенные формы 9 :
Комментарии:
Обратите внимание на пустые скобки в первой форме. C ++ и C отличаются в этом случае, потому что в C ++ это означает, что функция не принимает параметров. Но в C это означает, что он может принимать любой параметр.
C ++ 03 автономная среда
Имя функции, вызываемой при запуске, определяется реализацией. Если оно названо,
main()
оно должно следовать указанным формам 10 :C ++ 11 размещенная среда
Разрешенные формы 11 :
Комментарии:
Текст стандарта был изменен, но он имеет то же значение.
C ++ 11 автономная среда
Имя функции, вызываемой при запуске, определяется реализацией. Если оно названо,
main()
оно должно следовать указанным формам 12 :Ссылки
ANSI X3.159-1989 2.1.2.2 Размещенная среда. «Запуск программы»
ANSI X3.159-1989 2.1.2.1 Отдельно стоящая среда:
ISO 9899: 1999 5.1.2.2 Размещенная среда -> 5.1.2.2.1 Запуск программы
Обоснование международного стандарта - языки программирования - C, редакция 5.10. 5.1.2.2 Размещенная среда -> 5.1.2.2.1 Запуск программы
ISO 9899: 1999 5.1.2.2 Размещенная среда -> 5.1.2.2.3 Завершение программы
ISO 9899: 1999 5.1.2.1 Отдельно стоящая среда
ISO 9899: 2011 5.1.2.2 Размещенная среда -> 5.1.2.2.1 Запуск программы
Этот раздел идентичен C99, упомянутому выше.
ISO 9899: 1999 5.1.2.1 Отдельно стоящая среда
Этот раздел идентичен C99, упомянутому выше.
ISO 14882: 2003 3.6.1 Основная функция
ISO 14882: 2003 3.6.1 Основная функция
ISO 14882: 2011 3.6.1 Основная функция
ISO 14882: 2011 3.6.1 Основная функция
Этот раздел идентичен C ++ 03, приведенному выше.
источник
int my_startup_function ()
или,int my_startup_function (int argc, char *argv[])
но может ли она иметь, например:char my_startup_function (long argc, int *argv[])
как функцию запуска? Я думаю, нет, верно? Кроме того, не так ли двусмысленно?main()
потому что тогда она должна использовать одну из перечисленных подписей. Я полагаю, что наиболее распространенным из них будетvoid my_startup_function ()
, поскольку нет смысла возвращаться из программы на автономных системах.main
? Извините, если это не умный вопрос, но я не мог понять причины этого.func()
он считается устаревшим, сам черновик используетint main()
свои собственные примеры.Вернуть 0 в случае успеха и ненулевое значение в случае ошибки. Это стандарт, используемый сценариями UNIX и DOS для определения того, что случилось с вашей программой.
источник
main()
в C89 и K & R для неопределенных типов возвращаемых данных по умолчанию используется значение int.Если вы не введете оператор возврата
int main()
, закрытие{
вернет 0 по умолчанию.return 0
илиreturn 1
будет получен родительским процессом. В оболочке она переходит в переменную оболочки, и если вы запускаете свою программу из оболочки и не используете эту переменную, вам не нужно беспокоиться о возвращаемом значенииmain()
.См. Как я могу получить то, что вернула моя основная функция? ,
Таким образом, вы можете видеть, что это переменная,
$?
которая получает младший байт возвращаемого значенияmain()
.В Unix и DOS-сценариях
return 0
обычно возвращаются ошибки и ненулевые ошибки. Это стандарт, используемый сценариями Unix и DOS для выяснения того, что случилось с вашей программой и контроля всего потока.источник
$?
не является переменной среды; это предопределенная (или встроенная) переменная оболочки. Разницу трудно заметить, но если вы запуститеenv
(без каких-либо аргументов), она напечатает окружение и$?
не будет отображаться в окружении.{
» должно быть}
. ТАК не позволит мне сделать это небольшое редактирование.Имейте в виду, что, даже если вы возвращаете int, некоторые ОС (Windows) усекают возвращаемое значение до одного байта (0-255).
источник
unsigned
). То же самое в системах UNIX с 32-разрядными целыми числами. Но оболочки UNIX-стиля в любой системе обычно сохраняют только 8-разрядное целое число без знака.Возвращаемое значение может использоваться операционной системой для проверки того, как программа была закрыта.
Возвращаемое значение 0 обычно означает ОК в большинстве операционных систем (те, которые я могу думать в любом случае).
Это также может быть проверено, когда вы сами вызываете процесс, и смотрите, правильно ли программа завершилась.
Это НЕ просто соглашение о программировании.
источник
Возвращаемое значение
main()
показывает, как программа вышла. Если возвращаемое значение -zero
это означает, что выполнение было успешным, в то время как любое ненулевое значение будет означать, что что-то пошло не так в выполнении.источник
У меня сложилось впечатление, что стандарт определяет, что main не нуждается в возвращаемом значении, поскольку успешное возвращение основано на ОС (ноль в одном может быть либо успехом, либо неудачей в другом), поэтому отсутствие возврата было сигналом для компилятор для вставки самого успешного возврата.
Однако я обычно возвращаю 0.
источник
Возврат 0 должен сообщить программисту, что программа успешно завершила работу.
источник
main()
нормальных сигналов, произошла ошибка; возвращает 0 сигналов успеха. Если ваши программы всегда терпят неудачу, тогда 1 в порядке, но это не лучшая идея.1
изmain
определяется реализацией. Единственными значениями0
,EXIT_SUCCESS
определенными для языка, являются (часто определяемые как0
) иEXIT_FAILURE
. В OpenVMSreturn 1;
обозначает успешное завершение.Опустить
return 0
Когда программа на C или C ++ достигает конца,
main
компилятор автоматически сгенерирует код, возвращающий 0, поэтому нет необходимостиreturn 0;
явно указывать в концеmain
.Примечание: когда я делаю это предложение, за ним почти всегда следует один из двух видов комментариев: «Я этого не знал». или "Это плохой совет!" Мое обоснование заключается в том, что безопасно и полезно полагаться на поведение компилятора, явно поддерживаемое стандартом. Для C, так как C99; см. ИСО / МЭК 9899: 1999, раздел 5.1.2.2.3:
Для C ++, начиная с первого стандарта в 1998 году; см. ИСО / МЭК 14882: 1998 раздел 3.6.1:
С тех пор все версии обоих стандартов (C99 и C ++ 98) придерживались той же идеи. Мы полагаемся на автоматически сгенерированные функции-члены в C ++, и немногие люди пишут явные
return;
операторы в концеvoid
функции. Причины против пропуска, кажется, сводятся к «выглядит странно» . Если, как и я, вам интересно узнать причину изменения стандарта Си, прочитайте этот вопрос . Также обратите внимание, что в начале 1990-х это считалось «небрежной практикой», потому что в то время это было неопределенное поведение (хотя и широко поддерживаемое).Кроме того, основные руководящие принципы C ++ содержат несколько случаев пропуска
return 0;
в концеmain
и ни одного случая, в которых записан явный возврат. Хотя в этом документе пока нет конкретного руководства по этой конкретной теме, это, по крайней мере, является молчаливым одобрением этой практики.Так что я призываю опустить это; другие не согласны (часто яростно!). В любом случае, если вы столкнетесь с кодом, который его пропускает, вы будете знать, что он явно поддерживается стандартом, и вы будете знать, что это значит.
источник
return 0;
, однако я хотел бы отметить, что многие компиляторы той эпохи также реализовали неявныйreturn 0;
еще до того, как он был стандартизированы.return 0
уже более десяти лет. Также текущие версии Microsoft C поддерживают это также . Возможно, ваша информация устарела?Что вернуть, зависит от того, что вы хотите сделать с исполняемым файлом. Например, если вы используете вашу программу с оболочкой командной строки, вам нужно вернуть 0 для успеха и ненулевое значение для ошибки. Тогда вы сможете использовать программу в оболочках с условной обработкой в зависимости от результата вашего кода. Также вы можете назначить любое ненулевое значение согласно вашей интерпретации, например, для критических ошибок разные точки выхода из программы могут завершить программу с разными значениями выхода, и которая доступна вызывающей оболочке, которая может решить, что делать, проверив возвращаемое значение. Если код не предназначен для использования с оболочками и возвращаемое значение никого не беспокоит, его можно опустить. Я лично использую подпись
int main (void) { .. return 0; .. }
источник
main
совместим сint
. Поэтому возвращениеint
не будет проблемой. Хотя допускаются и другие возвращаемые типы, но в этом случае переменная среды, имеющая возвращаемое значение, не будет указана. Но если это делает программист,return 0;
то в bash его можно использовать для создания веток.Если у вас действительно есть проблемы, связанные с эффективностью возврата целого числа из процесса, вам, вероятно, следует избегать вызова этого процесса столько раз, что это возвращаемое значение становится проблемой.
Если вы делаете это (вызываете процесс так много раз), вы должны найти способ поместить свою логику непосредственно в вызывающую программу или в файл DLL, без выделения определенного процесса для каждого вызова; Многократное распределение процессов приносит вам соответствующую проблему эффективности в этом случае.
Подробно, если вы хотите узнать, является ли возврат 0 более или менее эффективным, чем возврат 1, в некоторых случаях это может зависеть от компилятора, но в общем случае, если они считываются из одного и того же источника (локального, поля, константы, встроенного в коде, результате функции и т. д.) требуется ровно столько же тактов.
источник
Вот небольшая демонстрация использования кодов возврата ...
При использовании различных инструментов, предоставляемых терминалом Linux, можно использовать код возврата, например, для обработки ошибок после завершения процесса. Представьте, что присутствует следующий текстовый файл myfile:
Когда вы выполняете команду grep, процесс создается. По завершении (и без прерывания) возвращается код от 0 до 255. Например:
Если вы делаете
вы получите 0. Почему? Потому что grep нашел совпадение и возвратил код выхода 0, который является обычным значением для успешного завершения. Давайте проверим это снова, но с чем-то, чего нет в нашем текстовом файле, и, следовательно, совпадение не будет найдено:
Поскольку grep не удалось сопоставить токен «foo» с содержимым нашего файла, код возврата равен 1 (это обычный случай, когда происходит сбой, но, как указано выше, у вас есть множество значений на выбор).
Теперь следующий скрипт bash (просто введите его в терминале Linux), хотя и очень простой, должен дать некоторое представление об обработке ошибок:
После второй строки ничего не выводится на терминал, так как «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
предотвращения появления совпадений или обычных сообщений об ошибках. Тем не менее, это мелочи оболочки - ключевой момент, что статус выхода может быть полезен - это нормально.Эти слова «(наиболее эффективные)» не меняют вопрос. Если вы не находитесь в автономной среде, есть один универсально правильный способ объявления
main()
, и это как возвращение int.Это не то, что должен
main()
вернуться, это то , что делаетmain()
возвращение.main()
это, конечно, функция, которую кто-то еще вызывает. Вы не имеете никакого контроля над кодом, который вызываетmain()
. Следовательно, вы должны объявитьmain()
с типо-правильной подписью, чтобы соответствовать вызывающей стороне. У вас просто нет выбора в этом вопросе. Вам не нужно спрашивать себя, что является более или менее эффективным, что лучше или хуже, или что-то в этом роде, потому что ответ для вас уже совершенно четко определен стандартами C и C +. Просто следуй за ними.0 для успеха, ненулевое значение для отказа. Опять же, не то, что вам нужно (или нужно) выбирать: это определяется интерфейсом, которому вы должны соответствовать.
источник