Каковы действительные подписи для функции main() в C?
Каковы действительные подписи для главной функции в C? Я знаю:
int main(int argc, char *argv[])
Есть ли другие действительные?
5 ответов
Текущий стандарт на момент этого ответа (C11) явно упоминает эти два:
int main(void);
int main(int argc, char* argv[]);
хотя он упоминает фразу "или эквивалент" со следующей сноской:
Таким образом,
int
может быть замененtypedef
имя определено какint
или типargv
можно записать какchar ** argv
, и так далее.
Кроме того, он также предоставляет больше (определенных реализацией) возможностей.
В соответствующем разделе (раздел 5.1.2.2.1 в C11, но этот конкретный аспект не отличается от C99) говорится:
Функция, вызываемая при запуске программы, называется основной. Реализация не объявляет прототип для этой функции. Он должен быть определен с типом возврата int и без параметров:
int main(void) { /* ... */ }
или с двумя параметрами (именуемыми здесь как argc и argv, хотя могут использоваться любые имена, так как они являются локальными для функции, в которой они объявлены):
int main(int argc, char *argv[]) { /* ... */ }
или эквивалент; или каким-либо другим способом, определяемым реализацией.
Если они объявлены, параметры главной функции должны подчиняться следующим ограничениям:
Значение
argc
должен быть неотрицательным.
argv[argc]
должен быть нулевым указателем.Если значение argc больше нуля, члены массива
argv[0]
черезargv[argc-1]
inclusive должен содержать указатели на строки, которым перед запуском программы передаются значения, определяемые реализацией хост-средой. Намерение состоит в том, чтобы предоставить программе информацию, определенную до ее запуска, из другой части размещенной среды. Если среда хоста не способна снабжать строки буквами как в верхнем, так и в нижнем регистре, реализация должна обеспечивать получение строк в нижнем регистре.Если значение
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
каждая из которых указывает на строку, которая предоставляет информацию о среде для этого выполнения программы (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++.)
В C есть разница между двумя обозначениями, но вы заметите это только в эзотерических случаях. В частности, есть разница, если вы называете main()
функция из вашего собственного кода, что вам разрешено делать в C и не разрешено делать в C++.
int main()
нотация не обеспечивает прототип для main()
, но это имеет значение, только если вы называете это рекурсивно. С int main()
Вы можете позже (в той же функции или в другой функции) написать int rc = main("absolute", "twaddle", 2):
и формально компилятор не должен жаловаться до такой степени, что отказывается компилировать код, хотя он может на законных основаниях жаловаться (предупреждать вас) об этом (и использовать -Werror
с помощью GCC преобразует предупреждение в ошибку). Если вы используете int main(void)
последующий вызов main()
должен выдать ошибку - вы сказали, что функция не принимает аргументов, но пыталась предоставить три. Конечно, вы не можете законно позвонить main()
до того, как вы объявили или определили его (если вы все еще не используете семантику C90) - и реализация не объявляет прототип для main()
, Примечание: стандарт 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)
Помимо обычного 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()