Каковы действительные сигнатуры для основной функции в C? Я знаю:
int main(int argc, char *argv[])
Существуют ли другие допустимые?
Каковы действительные сигнатуры для основной функции в C? Я знаю:
int main(int argc, char *argv[])
Существуют ли другие допустимые?
Текущий стандарт на момент этого ответа (C11) явно упоминает эти два:
int main(void);
int main(int argc, char* argv[]);
хотя он упоминает фразу "или эквивалент" со следующей сноской:
Таким образом,
int
может быть заменено именемtypedef
определенным какint
, или типargv
может быть записан какchar ** argv
и так далее.
Кроме того, он также предоставляет больше (определенных реализацией) возможностей.
В соответствующем разделе (раздел 5.1.2.2.1 раздела C11, но этот конкретный аспект не отличается от раздела C99) говорится:
Функция, вызываемая при запуске программы, называется
main
. Реализация не объявляет прототип для этой функции. Он должен быть определен с типом возвратаint
и без параметров:int main(void) { /* ... */ }
или с двумя параметрами (именуемыми здесь как
argc
иargv
, хотя могут использоваться любые имена, поскольку они являются локальными для функции, в которой они объявлены):int main(int argc, char *argv[]) { /* ... */ }
или эквивалент; или каким-либо другим способом, определяемым реализацией.
Если они объявлены, параметры
main
функции должны подчиняться следующим ограничениям:
Значение
argc
должно быть неотрицательным.
argv[argc]
должен быть нулевым указателем.Если значение
argc
больше нуля, члены массива отargv[0]
доargv[argc-1]
включительно должны содержать указатели на строки, которым перед установкой программы передаются значения, определяемые реализацией средой хоста. Намерение состоит в том, чтобы предоставить программе информацию, определенную до ее запуска, из другого места в размещенной среде. Если среда хоста не способна снабжать строки буквами как в верхнем, так и в нижнем регистре, реализация должна обеспечивать получение строк в нижнем регистре.Если значение
argc
больше нуля, строка, на которую указываетargv[0]
представляет имя программы;argv[0][0]
должен быть нулевым символом, если имя программы недоступно из среды хоста. Если значениеargc
больше единицы, строки, на которые указываютargv[1]
argv[argc-1]
представляют параметры программы.Параметры
argc
иargv
и строки, на которые указывает массивargv
должны изменяться программой и сохранять свои последние сохраненные значения между запуском программы и ее завершением.
Обратите внимание, что это для размещенной среды, которую вы обычно видите в программах на Си. Автономная среда (такая как встроенная система) гораздо менее ограничена, как указано в 5.1.2.1 того же стандарта:
В автономной среде (в которой выполнение программы на С может происходить без какой-либо выгоды от операционной системы), имя и тип функции, вызываемой при запуске программы, определяются реализацией. Любые библиотечные средства, доступные для автономной программы, кроме минимального набора, требуемого в разделе 4, определяются реализацией.
Для размещенной среды (это нормальная среда) стандарт 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, но в противном случае его тип определяется реализацией. Все реализации должны позволять оба следующих определения main:
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 Аргументы среды
In1 В размещенной среде основная функция получает третий аргумент
char *envp[]
, который указывает на массив указателей наchar
с нулевым символом вchar
, каждый из которых указывает на строку, предоставляющую информацию о среде для этого выполнения. программы (5.1.2.2.1).
Компилятор 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++.)
В 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, хотя между ними есть небольшая разница.
POSIX поддерживает execve()
, который, в свою очередь, поддерживает
int main(int argc, char *argv[], char *envp[])
Добавленный аргумент - это среда, то есть массив строк NAME = VALUE.
http://en.wikipedia.org/wiki/Main_function_(programming)#C_and_C.2B.2B
Помимо обычных int main(int argc, char *argv[])
и POSIX int main(int argc, char **argv, char **envp)
, в Mac OS X также поддерживается
int main(int argc, char* argv[], char* envp[], char* apple[]);
Конечно, это только для Mac.
В Windows есть
int wmain(int argc, wchar_t* argv[], wchar_t* envp[]);
как вариант Unicode (фактически, широко-символьный). Конечно, есть и WinMain
.
int main(void)
В некоторых ОС (например, Windows) также допустимо:
int main(int argc, char **argv, char **envp)
где envp
предоставляет среду, в противном случае доступную через getenv()