Яке правильне оголошення основного?


147

Яка правильна підпис mainфункції в C ++? Що таке правильний тип повернення і що означає повернути значення main? Які дозволені типи параметрів та які їх значення?

Ця система специфічна? Чи змінилися ці правила з часом? Що станеться, якщо я їх порушую?


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]гарантовано є нульовим покажчиком.

Зауважте, що оскільки аргумент типу масиву (подібний char*[]) насправді є просто маскуванням аргументу типу вказівника, наступні два - це дійсні способи запису (2), і вони означають абсолютно те саме:

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

Деякі реалізації можуть допускати інші типи та числа параметрів; вам доведеться перевірити документацію вашої реалізації, щоб побачити, що вона підтримує.

main()очікується, що поверне нуль, щоб вказувати на успіх, а не-нульовий - на знак провалу. Від вас не потрібно чітко писати returnзаяву в main(): якщо ви дозволите main()повернутися без явного 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. EDIT: Ага, гаразд, інші ненульові значення статусу можуть бути повернуті, але із значенням, визначеним реалізацією. Тільки EXIT_FAILURE гарантовано певним чином трактується як значення відмови.
Деррік Турк

4
@Synetech: У першому реченні питання задається питанням: "Яка правильна підпис основної функції в C ++?" і питання позначено як [c ++], так і [c ++ - faq]. Я не можу допомогти, якщо користувачі Java або C # (або хтось ще) все ще плутають. C # повинна Mainбути статичною функцією члена, оскільки вона навіть не має функцій нечлену. Навіть C89 вимагає mainповернення int. Я недостатньо знайомий з K&R C, щоб знати його точні правила, але я б припустив, що він також потребує mainповернення, intоскільки mainбез типу повернення було дещо поширеним, а тип intK = R не мається на увазі .
Джеймс Макнелл

3
@Suhail: Оскільки стандарт мови говорить, що тип повернення повинен бути int.
James McNellis

1
@Suhail: Так. Ваш код не буде правильним C ++, і багато компіляторів відкинуть ваш код.
James McNellis

2
@Suhail: Visual C ++ дозволяє voidтип повернення як розширення мови . До складу компіляторів, які не дозволяють, входять GCC та Comeau.
James McNellis

15

Зі стандартних документів, 3.6.1.2 Основна функція ,

Він повинен мати тип повернення типу int, але в іншому випадку його тип визначається реалізацією. Усі реалізації повинні дозволяти обидва наступні визначення основних:

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

В останньому вигляді argcзазначається кількість аргументів, переданих програмі із середовища, в якому запускається програма. Якщо argc не є нульовим, ці аргументи подаються в argv [0] через argv [argc-1] в якості вказівників до початкових символи багатобайтових рядків з нульовим завершенням .....

Сподіваюся, що це допомагає ..


2
Чи є якась конкретна причина того, чому mainповинен бути тип повернення int?
Suhail Gupta

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не має виведеного типу повернення. Зверніть увагу на {in "(auto main () {... не дозволено)", і будь ласка, навчіться знати, коли ви ще не знаєте достатньо, щоб додати щось значуще.

3

Дві дійсні електромережі є int main()і int main(int, char*[]). Будь-яке інше може або не може складати. Якщо mainявно не повертає значення, 0 повертається неявно.


1
Я ніколи не бачив, щоб код не збирався, коли я згадую тип повернення, mainщоб бути недійсним. Чи є якась конкретна причина того, що тип повернення основного повинен бути int?
Suhail Gupta

4
Специфікація мови говорить, що основний повинен мати тип повернення int. Будь-який інший тип повернення, дозволений компілятором, є специфічним для компілятора доповненням. В основному використання void означає, що ви програмуєте мовою, подібною, але не C ++.
кам’яний метал

2
Причина, яку стандарт вимагає intяк тип повернення, mainполягає в тому, що це значення передається оболонці як вихідний код програми, і shочікує, що воно буде int.
uckelman

Може, причина - дисципліна? Вихід може бути більше ніж один. Якщо тип повернення є, voidвони всі мовчать. З intми повинні визначити конкретні екзит-значення для кожного повернення з main.
Андреас Шпіндлер

2

Детальніше про повернені значення та їх значення

За 3.6.1 ( [basic.start.main]):

Оператор повернення у програмі mainмає наслідком залишення mainфункції (знищення будь-яких об'єктів з автоматичною тривалістю зберігання) та виклик std::exitіз значенням повернення в якості аргументу. Якщо контроль доходить до кінця, mainне стикаючись із returnтвердженням, ефект буде виконати

return 0;

Поведінка std::exitдетально описана у розділі 18.5 ( [support.start.term]) та описує код статусу:

Нарешті, контроль повертається у головне середовище. Якщо статус дорівнює нулю або EXIT_SUCCESSповертається визначена реалізацією форма успішного припинення статусу. Якщо статус є EXIT_FAILURE, повертається визначена реалізацією форма невдалого припинення статусу. Інакше повернутий статус визначається реалізацією.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.