Тип возврата основной функции

Возможный дубликат:
Что должно возвращать main() в C/С++?
Разница между void main и int main?

Я всегда использовал основной метод в C, например

void main(){ // my code }

и это работает очень хорошо для меня. Я также знаю о другом возвращаемом типе int:

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

Но я не смог найти какой-либо ресурс, который говорит, что я могу использовать void как возвращаемый тип. Каждая книга предполагает, что тип возврата должен быть int, иначе он будет опущен. Тогда почему работает void main()?

Является ли это зависимым от версии C, которую я использую? Или это работает, потому что я использую С++ IDE? Ответьте на вопрос C, а не на С++.

Ответ 1

Только авторы книг, похоже, относятся к месту, где разрешен тип возврата void для main(). Стандарт С++ запрещает его полностью.

В стандарте C говорится, что стандартные формы:

int main(void) { ... }

и

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

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

Стандарт C делает небольшое положение для "в некоторой другой определенной реализации". В стандарте ISO/IEC 9899: 2011 говорится:

5.1.2.2.3 Окончание программы

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

11) В соответствии с 6.2.4 время жизни объектов с автоматическим временем хранения, объявленным в основном закончится в первом случае, даже если они не были бы в последнем.

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

(Хотя я цитирую стандарт C2011, по сути, те же слова были на C99, и я считаю C89, хотя мой текст для этого находится в офисе, а я нет.)

Кстати, в Приложении J стандарта упоминается:

J.5 Общие расширения

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

J.5.1 Аргументы среды

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

Почему работает void main()?

В вопросе отмечается, что void main() работает. Он работает, потому что компилятор делает все возможное, чтобы генерировать код для программ. Компиляторы, такие как GCC, будут предупреждать о нестандартных формах для main(), но будут обрабатывать их. Линкер не слишком беспокоится о типе возврата; ему просто нужен символ main (или, возможно, _main, в зависимости от системы), и когда он его найдет, связывает его с исполняемым файлом. Код запуска предполагает, что main был определен стандартным образом. Если main() возвращается к коду запуска, он собирает возвращаемое значение, как если бы функция возвращала int, но это значение, скорее всего, будет мусором. Таким образом, это похоже на работу, пока вы не ищете статус выхода вашей программы.

Ответ 2

Из лошадиного устья:

5.1.2.2.1 Запуск программы

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

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

    int main(int argc, char *argv[]) { /* ... */ }
или эквивалент; 9) или каким-либо другим способом, определяемым реализацией.
9) Таким образом, int можно заменить на имя typedef, определенное как int, или тип argv можно записать как char ** argv и т.д.

Лазейка - это "какой-то другой способ реализации". Реализация может позволить main возвращать void (или любой другой тип), но он должен явно документировать, что такая подпись разрешена. В противном случае поведение undefined, что означает, что компилятор может делать все, что он хочет. Программа может выполняться без каких-либо проблем. Он может выполняться, но оставить среду в плохом состоянии. При выходе может произойти сбой. Он может вообще не загружаться.

Ответ 3

Это зависит от используемого вами компилятора, но void main не компилируется повсюду. Я видел компиляторы, которые не будут компилировать программу с void main. Я не могу вспомнить конкретный случай (для c), но я точно знаю, что это происходит в g ​​++ (да, я знаю, что это С++).

Ответ 4

Стандартные вызовы main() для возврата int, но многие компиляторы C позволяют указать тип возврата main() как void.

Я рекомендую вам привыкнуть возвращаться int. Добавление

return 0;

до конца вашего main() не слишком много усилий.