Каковы на самом деле действительные подписи для основной функции в 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
, но этот конкретный аспект не изменился с 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
, должны изменяться программой и сохранять свои последние сохраненные значения между запуском программы и ее завершением.
Обратите внимание, что это для размещенной среды, той, которую вы обычно видите в программах на C. Автономная среда (например, встроенная система) гораздо менее ограничена, как указано в 5.1.2.1
того же стандарта:
В автономной среде (в которой выполнение программы C может происходить без каких-либо преимуществ операционной системы) имя и тип функции, вызываемой при запуске программы, определяются реализацией. Любые библиотечные средства, доступные для автономной программы, кроме минимального набора, требуемого разделом 4, определяются реализацией.
int main(int argc, const char* argv[]);
?
- person potrzebie; 15.08.2013
int main(int argc, char* const argv[]){...}
, сделав сам параметр параметром константным. Я бы подумал, что это оправданно, потому что оно совместимо с предполагаемым неявным объявлением int main(int argc, char* argv[]);
.
- person Peter - Reinstate Monica; 19.06.2019
argv[3]
, чтобы он указывал на совершенно другую строку, эта возможность теряется, если вы const
отдельные указатели. Я подозреваю, что это не будет отличаться от const char *argv[]
, который лишит вас возможности изменять символы с помощью аргументов (например, argv[3][1] = '\0'
, чтобы заставить его использовать только первый символ).
- person paxdiablo; 20.06.2019
argc
и argv
и строки, на которые указывает массив argv
, должны быть изменены программой, которая может вступить в игру, хотя ее можно читать только как argv
и символы, указывающие на by argv[N]
, не отдельные указатели, составляющие argv
. Поэтому в стандартах нет места неряшливой лексике :-)
- person paxdiablo; 20.06.2019
argv
(собственно), безусловно, можно изменять (поскольку он, как и все параметры функции, является локальной копией), но функция реализация может свободно заявить, что она воздерживается от изменения этого локальная переменная, объявив ее константой, без изменения сигнатуры функции. Стандарт означает, что argv не указывает на константную память, как и указатели в этой неконстантной памяти (то есть, что мы можем сказать ++argv
, само собой разумеется, но стандарт требует, чтобы мы также могли сказать ++*argv
и даже ++**argv
(если argc ›0).
- person Peter - Reinstate Monica; 20.06.2019
Для размещенной среды (это нормальная) стандарт 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 ++ явно говорит, что It [основная функция] должна иметь возвращаемый тип типа 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 (несмотря на предыдущие версии этого ответа).
Это признано стандартом C как общее расширение, задокументированное в Приложении J:
### J.5.1 Аргументы среды
¶1 В размещенной среде основная функция получает третий аргумент,
char *envp[]
, который указывает на массив указателей с завершающим нулем на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, хотя между ними есть небольшая разница.
main
изнутри программы - это UB в C ++; компиляторам разрешено вставлять вызовы статических конструкторов в начало main или что-то еще. Я думаю, что это разрешено в Си. (Но вы можете обнаружить, что ICC сбрасывает режимы среды / округления FP, потому что он вызывает функцию Intel init из верхней части main.)
- person Peter Cordes; 19.06.2019
C11
текст, который позволяет вам сказать (выделенная жирным шрифтом фраза): NB: Стандарт C11 иллюстрирует как int main (), так и int main (void) в разных примерах - оба действительны в C,. Я действительно вижу этот точный синтаксис в C11
, но не нашел содержимого, в котором прямо указано, что он действителен. Но тогда у меня нет опыта в правильной интерпретации того, что я вижу в стандарте. Должны ли мы интерпретировать то, что, если конкретный синтаксис существует в качестве иллюстрации в этом стандарте, он должен считаться законным (или действительным)?
- person ryyker; 16.09.2020
int main() { … }
эквивалентно int main(void) { … }
.
- person Jonathan Leffler; 16.09.2020
int main();
и int main(void);
не эквивалентны. Оба объявляют (а не определяют) функцию, но в первом ничего не указывается в списке параметров (не предоставляется прототип функции), а во втором явно говорится, что функция не принимает аргументов. (Разница между объявлением и определением заключается в том, почему в предыдущем комментарии есть int main() { … }
, обозначающее определение функции, тогда как здесь { … }
заменено точкой с запятой, обозначающей объявление функции.)
- person Jonathan Leffler; 16.09.2020
int main() { … }
эквивалентно int main(void) { … }
. Затем в первом утверждении во втором комментарии вы, кажется, делаете противоположное утверждение: Обратите внимание, что int main();
и int main(void);
не эквивалентны. Я считаю, что в целом я истолковал, что эти два не эквивалентны, поскольку один (int main();
) может быть продемонстрирован для размещения нескольких аргументов, а другой не сможет скомпилировать ни с какими аргументами.
- person ryyker; 16.09.2020
int main() { … }
и int main(void) { … }
не эквивалентны, потому что первый все еще не предоставляет прототип для main()
, тогда как последний делает. Оба, однако, определяют функцию, которая не принимает аргументов (и в этом смысле они эквивалентны - это то, что я должен был сказать, но в комментарии не хватало места). Единственный раз, когда разница имеет значение, это если ваш код вызывает main()
рекурсивно (или беспорядок с указателями функций на main()
) - ни то, ни другое не является повседневным занятием для программистов C (а рекурсивные вызовы запрещены в C ++).
- person Jonathan Leffler; 16.09.2020
POSIX поддерживает execve()
, который, в свою очередь, поддерживает
int main(int argc, char *argv[], char *envp[])
Добавленный аргумент - это окружение, то есть массив строк в форме ИМЯ = ЗНАЧЕНИЕ.
extern char **environ;
.
- person R.. GitHub STOP HELPING ICE; 02.06.2011
envp
аргумент main
. Я не уверен, указывает ли сам POSIX это как 3-ю действительную подпись для main
или нет. Вы можете убедиться, что это работает на практике в GNU C с помощью этой программы: godbolt.org/z/9lie95 (он передает свои argv и envp в execve("/usr/bin/env")
, поэтому вы можете видеть, что он унаследовал нормальную среду вместо того, чтобы возвращать -EFAULT
). Но да, этот ответ описывает это неправильно, подразумевая, что существование execve подразумевает новую подпись для main
.
- person Peter Cordes; 19.06.2019
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()
main()
на C и C ++?, но он был вновь открыт в июле 2017 года после почти 5-летнего перерыва. Информация, содержащаяся в ответах, повторяется в ответах на этот вопрос. - person Jonathan Leffler   schedule 14.09.2018main()
?, хотя он был создан после этого вопроса и является строго вопросом C ++, поэтому его дублирование не совсем подходит. - person Jonathan Leffler   schedule 14.09.2018