Стандарт С
Для размещенной среды (это нормальная среда) стандарт C99 гласит:
5.1.2.2.1 Запуск программы
Функция, вызываемая при запуске программы, называется main
. Реализация заявляет нет
прототип для этой функции. Он должен быть определен с типом возврата int
и без
Параметры:
int main(void) { /* ... */ }
или с двумя параметрами (именуемыми здесь argc
и argv
, хотя любые имена могут быть
используется, поскольку они являются локальными для функции, в которой они объявлены):
int main(int argc, char *argv[]) { /* ... */ }
или эквивалентный; 9) или другим способом, определяемым реализацией.
9) Таким образом, int
может быть заменено именем typedef, определенным как int
, или тип argv
может быть записан как
char **argv
и т. Д.
Стандарты C11 и C18 в основном соответствуют стандарту C99.
Стандарт С ++
Стандарт C ++ 98 гласит:
3.6.1 Основная функция [basic.start.main]
1 Программа должна содержать глобальную функцию main, которая является назначенным началом программы. [...]
2 Реализация не должна предопределять основную функцию. Эта функция не должна быть перегружена. Это должно
иметь тип возвращаемого значения типа int, но в противном случае его тип определяется реализацией.
Все реализации
должно допускать оба следующих определения основных:
int main() { /* ... */ }
и
int main(int argc, char* argv[]) { /* ... */ }
Стандарт C ++ прямо говорит: «Он [основная функция] должен иметь тип возвращаемого значения типа int, но в противном случае его тип определяется реализацией», и для него требуются те же две подписи, что и для стандарта C. Таким образом, void main () напрямую не разрешен стандартом C ++, хотя он ничего не может сделать, чтобы мешать нестандартной соответствующей реализации не допускать альтернативы (ни стандартной соответствующей реализации не разрешать альтернативы в качестве расширений стандарта).
Стандарты C ++ 03, C ++ 11, C ++ 14 и C ++ 17, по сути, совпадают с C ++ 98.
Общее расширение
Классически системы Unix поддерживают третий вариант:
int main(int argc, char **argv, char **envp) { ... }
Третий аргумент - это список указателей на строки с нулевым символом в конце, каждый из которых является переменной окружения, которая имеет имя, знак равенства и значение (возможно, пустое). Если вы не используете это, вы все равно можете попасть в окружение через 'extern char **environ;
'. Долгое время у этого не было заголовка, который объявил его, но стандарт POSIX 2008 теперь требует, чтобы он был объявлен в <unistd.h>
.
Это признано стандартом C как общее расширение, документированное в Приложении J:
J.5.1 Аргументы среды
¶1 В размещенной среде главная функция получает третий аргумент, char *envp[]
,
который указывает на массив указателей с нулевым символом в конце на char
, каждый из которых указывает на строку
который предоставляет информацию о среде для выполнения программы (5.1.2.2.1).
Microsoft C
Компилятор Microsoft VS 2010 интересен. На сайте написано:
Синтаксис объявления для main:
int main();
или, необязательно,
int main(int argc, char *argv[], char *envp[]);
В качестве альтернативы функции main
и wmain
могут быть объявлены как возвращающие void
(без возвращаемого значения). Если вы объявляете main
или wmain
как возвращающие void, вы не можете вернуть код завершения родительскому процессу или операционной системе с помощью оператора return. Чтобы вернуть код выхода, когда main
или wmain
объявлен как void
, необходимо использовать функцию exit
.
Мне не ясно, что происходит (какой код завершения возвращается родителю или o / s), когда программа с void main()
завершает работу - и веб-сайт MS тоже молчит.
Интересно, что MS не предписывает версию main()
с двумя аргументами, которая требуется для стандартов C и C ++. Он только предписывает форму с тремя аргументами, где третий аргумент - char **envp
, указатель на список переменных среды.
На странице Microsoft также перечислены некоторые другие альтернативы - wmain()
, который принимает строки широких символов, и некоторые другие.
Microsoft VS 2005 версия на этой странице не перечисляет void main()
в качестве альтернативы. версии от Microsoft VS 2008 года и старше.
Является ли int main()
таким же, как int main(void)
?
Подробный анализ см. В конце моего ответа на Что должен main()
вернуть в C и C ++ . (Кажется, я когда-то считал, что этот вопрос относится к C ++, хотя это не так и никогда не было. В C ++ нет разницы между int main()
и int main(void)
и int main()
идиоматическим C ++.)
В Си есть разница между двумя обозначениями, но вы замечаете это только в эзотерических случаях. В частности, есть разница, если вы вызываете функцию main()
из своего собственного кода, что вам разрешено делать в C и не разрешено делать в C ++.
Запись int main()
не предоставляет прототип для main()
, но это имеет значение, только если вы вызываете его рекурсивно. С int main()
вы могли бы позже (в той же функции или в другой функции) написать int rc = main("absolute", "twaddle", 2):
, и формально компилятор не должен жаловаться на степень отказа в компиляции кода, хотя он может обоснованно жаловаться (предупреждаю) об этом (и использование -Werror
с GCC превратит предупреждение в ошибку). Если вы используете int main(void)
, последующий вызов main()
должен выдать ошибку - вы сказали, что функция не принимает аргументов, но попытались предоставить три. Конечно, вы не можете законно вызвать main()
до того, как объявите или определили его (если только вы не используете семантику C90) - и реализация не объявляет прототип для main()
. NB. Стандарт C11 иллюстрирует как int main()
, так и int main(void)
в разных примерах - оба действительны в C, хотя между ними есть небольшая разница.