Что такое правильное объявление основного?

147

Какова правильная подпись mainфункции в C ++? Каков правильный тип возвращаемого значения и что означает возвращать значение main? Каковы допустимые типы параметров и каковы их значения?

Это зависит от системы? Изменились ли эти правила с течением времени? Что произойдет, если я нарушу их?

fredoverflow
источник
1
Это очень тесно связано с тем, что должно mainвозвращаться в C и C ++ , или является его копией .
Джонатан Леффлер
@JonathanLeffler Без шуток ... он был добавлен в список дубликатов в редакции 6 около 8 месяцев назад.
fredoverflow

Ответы:

192

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

Имя mainне зарезервировано в C ++ за исключением функции в глобальном пространстве имен. Вы можете объявлять другие именованные сущности main, в том числе классы, переменные, перечисления, функции-члены и функции, не являющиеся членами, не входящие в глобальное пространство имен.

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

mainФункция не может быть объявлена как staticили inline. Это также не может быть перегружено; mainв глобальном пространстве имен может быть только одна функция .

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

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

Есть две декларации, mainкоторые должны быть разрешены:

int main()               // (1)
int main(int, char*[])   // (2)

В (1) нет параметров.

В (2) есть два параметра, и они условно названы argcи argv, соответственно. argvявляется указателем на массив строк C, представляющих аргументы программы. argcколичество аргументов в argvмассиве

Обычно argv[0]содержит название программы, но это не всегда так. argv[argc]гарантированно будет нулевым указателем.

Обратите внимание, что поскольку аргумент типа массива (like char*[]) на самом деле является просто скрытым аргументом типа указателя, следующие два являются допустимыми способами write (2), и оба они означают одно и то же:

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

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

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

int main() { }
int main() { return 0; }

Есть два макроса, EXIT_SUCCESSи EXIT_FAILURE, определенные в <cstdlib>этом, также могут быть возвращены из, main()чтобы указать успех и неудачу, соответственно.

Возвращаемое значение main()передается в exit()функцию, которая завершает программу.

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

Джеймс МакНеллис
источник
1
IIRC единственные гарантированные возвращаемые значения: 0, EXIT_SUCCESS (тот же эффект, что и 0) и EXIT_FAILURE. РЕДАКТИРОВАТЬ: Ах, хорошо, другие ненулевые значения статуса могут быть возвращены, но с определенным реализацией значением. Только EXIT_FAILURE гарантированно интерпретируется как значение ошибки.
Деррик Тюрк
4
@Synetech: в первом предложении вопрос звучит так: «Какова правильная сигнатура главной функции в C ++?» и вопрос помечен как [c ++] и [c ++ - faq]. Я не могу помочь, если пользователи Java или C # (или кто-либо еще) все еще в замешательстве. C # Mainдолжен быть статической функцией-членом, потому что он даже не имеет функций, не являющихся членами. Даже С89 требует mainвернуть int. Я недостаточно знаком с K & R C, чтобы знать его точные правила, но я предполагаю, что он также требует mainвозврата, intпоскольку mainотсутствие типа возврата было довольно распространенным явлением и отсутствие типа = неявное intв K & R.
Джеймс МакНеллис
3
@Suhail: Поскольку языковой стандарт говорит, что тип возвращаемого значения должен быть int.
Джеймс МакНеллис
1
@Suhail: Да. Ваш код не будет корректным C ++, и многие компиляторы отклонят ваш код.
Джеймс МакНеллис
2
@Suhail: Visual C ++ допускает voidтип возвращаемого значения как расширение языка . Компиляторы, которые не разрешают это, включают GCC и Comeau.
Джеймс МакНеллис
15

Из стандартных документов. 3.6.1.2 Основная функция ,

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

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

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

Надеюсь, это поможет..

liaK
источник
2
Есть ли какая-то конкретная причина того, почему mainдолжен быть возвращаемый тип int?
Сухаил Гупта
1
@SuhailGupta: чтобы вызывающий процесс знал, следует ли считать этот процесс успешным или нет. Позволяет voidломать эту модель. Это даже не имеет смысла, если бы вы имели в виду «всегда считаю успехом». Потому что вы не могли сказать, действительно ли процесс провалился, так ли вы действительно преуспели? Нет, вернись int.
Гонки
4

Точная формулировка последнего опубликованного стандарта (C ++ 14):

Реализация должна позволять как

  • функция ()возврата intи

  • функция (int, указатель на указатель на char)возвращаемыйint

как тип main.

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

  • int main(void)
  • auto main() -> int
  • int main ( )
  • signed int main()
  • typedef char **a; typedef int b, e; e main(b d, a c)
М.М.
источник
1
NB. Я опубликовал этот ответ, как в комментариях к другой ветке, кто-то пытался привести эту ветку в качестве доказательства, что int main(void)она не верна в C ++.
ММ
3
@Stargateur auto main() -> intне имеет выведенного типа возврата. Обратите внимание на {в "(auto main () {... не разрешено)" и, пожалуйста, научитесь знать, когда вы еще не знаете достаточно, чтобы добавить что-то значимое.
3

Две действительные сети являются int main()и int main(int, char*[]). Любая вещь может компилироваться или не компилироваться. Если mainявно не возвращает значение, 0 неявно возвращается.

stonemetal
источник
1
Я никогда не видел, чтобы код не компилировался, когда я упоминал тип возврата mainvoid. Есть ли конкретная причина, по которой тип возвращаемого значения main должен быть int?
Сухаил Гупта
4
В спецификации языка сказано, что main должен иметь тип возвращаемого значения int. Любой другой тип возвращаемого значения, разрешенный вашим компилятором, является специфическим улучшением компилятора. По сути, использование void означает, что вы программируете на языке, похожем на C ++, но не на этом.
каменный металл
2
Причиной, по которой стандарт требует использования intтипа возврата, mainявляется то, что это значение передается оболочке как код завершения программы и shожидает значение int.
Uckelman
Может быть, причина в дисциплине? Может быть более одного выхода. Если возвращаемый тип - voidони все молчат. С помощью intмы должны определить конкретное значение выхода для каждого возврата из main.
Андреас Шпиндлер
2

Подробности о возвращаемых значениях и их значении

Согласно 3.6.1 ( [basic.start.main]):

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

return 0;

Поведение std::exitподробно описано в разделе 18.5 ( [support.start.term]) и описывает код состояния:

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

Бен Фойгт
источник