Перегружен ли main () в C ++?

В C++ существуют 2 действующие версии main():

int main()  // version 1
int main(int argc, char **argv)  // version 2

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

Выполняет ли компилятор специальную проверку, позволяющую использовать только одну версию для каждого двоичного файла?


person iammilind    schedule 20.06.2011    source источник
comment
прочитав ваш вопрос, даже я очень хочу это знать   -  person Devjosh    schedule 20.06.2011
comment
Голосование вниз (это не имеет значения, но просто для вашего внимания), для пометки вопроса с помощью C, когда это чистый вопрос C ++ (т.е. C не поддерживает перегрузки, заголовок и первая строка явно указывают на то, что это C ++ ). Избегайте смешивания языков, которые не совпадают, в вопросах, касающихся явно различных функций.   -  person David Rodríguez - dribeas    schedule 20.06.2011
comment
@David, я намеренно поставил тег C, потому что в C также разрешены несколько версий main(). Более того, void main() не поддерживается в C ++, но в основном действует в C. Однако, упоминая C++ в вопросе, я не возражал.   -  person iammilind    schedule 20.06.2011
comment
void main() также не является допустимым C, если вы говорите о Standard C (C89, C90, C99).   -  person Nawaz    schedule 20.06.2011
comment
если вы не передаете аргумент, то 1-я версия должна называться иначе 2-я версия. Вызывается тот, который содержится в программе. Если программа содержит версию без аргументов, аргументы командной строки игнорируются. Если программа содержит вторую версию и нет аргументов, тогда argc равно 1, а argv содержит указатель на имя программы, за которым следует нулевой указатель. Так что даже если бы вы могли его перегрузить, вы бы не захотели такого поведения, поскольку даже без аргументов все еще существует пара argc / argv.   -  person Steve Jessop    schedule 20.06.2011
comment
@glglgl, пожалуйста, прочтите мой комментарий выше, этот вопрос в равной степени применим и к C. Спасибо.   -  person iammilind    schedule 23.05.2012
comment
@iammilind Да, но в C нет перегрузки, поэтому два main() никогда не могут сосуществовать. И C также не выполняет манипуляции, зависящие от сигнатур.   -  person glglgl    schedule 23.05.2012


Ответы (6)


§3.6.1 / 2 (C ++ 03) говорит

Реализация не должна предопределять функцию main. Эта функция не должна быть перегружена. Она должна иметь тип возвращаемого значения int, но в остальном ее тип определяется реализацией. Все реализации должны допускать оба следующих определения main:

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

Вы можете использовать любой из них. Оба соответствуют стандарту.

Кроме того, поскольку char *argv[] эквивалентно char **argv, замена char *argv[] на char **argv не имеет никакого значения.


Но обе версии не могут сосуществовать одновременно! (вариант использования может быть таким: при запуске двоичного файла из командной строки, если вы не передаете аргумент, то 1-я версия должна называться иначе 2-я версия).

Нет. Обе версии не могут сосуществовать одновременно. Одна программа может иметь ровно одну main функцию. Какой именно, зависит от вашего выбора. Если вы хотите обработать аргумент командной строки, вы должны выбрать вторую версию, иначе первой версии будет достаточно. Также обратите внимание, что если вы используете вторую версию и не передаете аргумент командной строки, то это не причинит вреда. Это не вызовет никаких ошибок. Вам просто нужно интерпретировать argc и argv соответственно, и на основе их значения вы должны написать логику и последовательность действий вашей программы.

person Nawaz    schedule 20.06.2011
comment
Учитывая, что вопрос размечен для двух языков, непонятно, какой стандарт вы цитируете ... - person Tony Delroy; 20.06.2011
comment
@Tony: учитывая, что вопрос действительно касается overload s, а C не поддерживает перегрузки, я могу только предположить, что тег C используется неправильно. Ну, а также тот факт, что заголовок и первая строка явно указывают на то, что обсуждение C ++. - person David Rodríguez - dribeas; 20.06.2011
comment
@Tony: Я уже упоминал об этом. Кроме того, This function shall not be overloaded дает понять, что его C ++. В конце концов, C не поддерживает перегрузку любой функции. - person Nawaz; 20.06.2011
comment
@David, @Nawaz: в стандарте C также обсуждаются ссылки, но этот термин используется в общем контексте. научный смысл смысла указателем. Точно так же можно спросить, не перегружен ли main() в C, т.е. компилятор генерирует отдельные копии в исполняемом файле, а загрузчик решает, что вызывать. Общий ответ: нет - только ...(argc, argv[, envp]) скомпилировано / вызвано - неиспользуемые аргументы в порядке. Но комментарии к другим ответам идентифицируют примеры этой концепции перегрузки - разные точки входа DOS и Windows. Очевидно, что все это отличается от перегрузки C ++ - линкер, а не язык разрешает вызов. - person Tony Delroy; 21.06.2011
comment
@Tony, main на самом деле не точка входа в программу, это первая (основная) функция, которую нужно вызвать, но статическая инициализация должна произойти до main. . Я сомневаюсь, что DOS / Windows имеют разные точки входа для приложений (это может быть, если существуют разные исполняемые форматы), и я также сомневаюсь, что в случае wmain, _tmain и WinMain программа не содержит простой main функции (определенной в библиотеке и связан), который перенаправляет вызов ... но мне нужно было бы иметь среду Windows, чтобы действительно проверить это, поэтому я не буду утверждать, что это правда - person David Rodríguez - dribeas; 21.06.2011
comment
@David: Я тоже не эксперт по Windows ... просто обсуждаю терминологию, намерения и широту вопроса. iammilind отвечает в третьем комментарии на свой вопрос, подтверждая свое намерение использовать терминологию в общем виде, включая C. - person Tony Delroy; 21.06.2011
comment
Рассуждения Дэвида о том, как работают точки входа в Windows, совершенно верны. В коде библиотеки спрятана простая main функция. То, что вы видите _tWinMain, не является официальной точкой входа, это всего лишь точка входа в отношении вашего кода. - person Cody Gray; 22.06.2011

В Windows и Unix есть:

int main(int argc, char **argv, char **envp)

и приложения Win32 имеют:

int WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);

а в MacOS есть:

int main(int argc, char **argv, char **envp, char **apple)

Не забывайте, что main обычно не первое, что вызывает ОС при выполнении программы. Функция main - это функция, вызываемая средой выполнения. Адрес первой выполняемой инструкции обычно объявляется в некоторых метаданных, обычно в начале исполняемого файла.

Насколько я могу судить, ничто из вышеперечисленного не противоречит стандарту C / C ++, поскольку существует только один, что имеет смысл, поскольку ОС не знала бы, что вызывать, если бы их было больше. Проверка только одного не выполняется в компиляторе, а в компоновщике.

person Skizz    schedule 20.06.2011
comment
Мне интересно, можно ли увидеть MSVC несовместимым с w.r.t. WinMain? Поскольку функция входа определяется как _2 _... (помимо всего прочего несовместимого материала в MSVC.) - person Xeo; 20.06.2011
comment
@Xeo: Это в основном предел ... VS создает для вас функцию main, которая выполняет определенную инициализацию перед вызовом вашей функции WinMain. Точкой входа в программу по-прежнему является main, только в этом случае это не ваша главная. Кажется, что это противоречит §3.6.1 / 2 Реализация не должна предопределять основную функцию., но если они могут гарантировать, что это не повлияет на ваши программы (т.е. если вы определите main, она будет использовать ваши версия, а не его собственная), он может вести себя как если бы, чего достаточно. - person David Rodríguez - dribeas; 20.06.2011
comment
... и в то же время другие библиотеки делают то же самое (большинство фреймворков модульного тестирования предоставят вам main, если вы захотите. В этот момент возникает философское обсуждение того, генерируется ли main компилятором или скомпоновано как библиотека и все серое. Меня бы это особо не волновало, я видел и похуже в других местах ... Symbian C ++ является одним из них - person David Rodríguez - dribeas; 20.06.2011
comment
MSVC также имеет int wmain(int argc, wchar_t* argv[]); и _tmain: -. / - см. Заголовок stackoverflow.com/questions/895827/ - person Tony Delroy; 20.06.2011
comment
@David: Ну, если библиотека предоставляет main, это нормально в соответствии со стандартом. :) - person Xeo; 20.06.2011
comment
@David Rodríguez: у приложений IIRC Win32 есть две точки входа: WinMain, которую использует Windows, и точка входа DOS при вызове из DOS (раньше просто говорилось, что по умолчанию этой программе нужна Windows, но ее можно переопределить). Не уверен, какой из них используется, если вы определяете main. - person Skizz; 20.06.2011
comment
Фактическая точка входа в Win32 (в приложениях, скомпилированных MSVC - фактическая функция указывается в exe) называется чем-то вроде WinMainCrtStartup [это другое, если у вас WinMain vs main], которая вызывается непосредственно какой-либо функцией в kernel32.dll, а в Turn вызывает WinMain, main или что-то еще. Это отдельно от заглушки DOS, о которой вы думаете, в которой говорится, что программе нужны окна. - person Random832; 20.06.2011
comment
envp не гарантируется стандартом. - person RastaJedi; 17.03.2019

Раздел 3.6.1.2 редакции C ++ Standard 1998 и 2003 гласит:

Реализация не должна предопределять основную функцию. Эту функцию нельзя перегружать. Он должен иметь возвращаемый тип типа int, но в остальном его тип определяется реализацией.

Дальше,

Стандарт ISO C ++ (ISO / IEC 14882: 1998) конкретно требует, чтобы main возвращал int. Он имеет явное ограничение "должен" на правильно сформированные программы.

Раздел § 3.6.1 ¶ 2:

Он должен иметь возвращаемый тип int, но в остальном его тип определяется реализацией. Все реализации должны допускать оба следующих определения main:

int main() { /* … */ }

и

int main(int argc, char* argv[]) { /* … */ }

Таким образом, обе версии main разрешены стандартом, а какую из них использовать, остается на усмотрение программиста.

person Alok Save    schedule 20.06.2011
comment
Nitpick: обычно деталь реализации используется в контексте реализации компилятора + набора инструментов, в то время как в этом случае решение остается за пользователем этой реализации: то есть вы программист. - person David Rodríguez - dribeas; 20.06.2011
comment
@ Дэвид Родригес - dribeas: Хорошо сказано. У меня была небольшая путаница по поводу того, что implementation detail явно используется в контексте компилятора и набора инструментов или в общем виде. Я изменил его, я собирался упомянуть об этом таким образом, но затем я подумал проверить, может ли кто-нибудь указать, неправильно использовать его в общем виде, и вы это сделали! :) - person Alok Save; 20.06.2011

Main был определен еще во времена C. Он настраивается в соответствии с правилами printf. Рассматривайте main как варадическую функцию:

int main(...)

Стандарт говорит, что никаких аргументов и два аргумента-указателя - это нормально. Однако, если реализация хочет предоставить больше аргументов, она может это сделать.

Причина, по которой у вас не может быть двух main, - это та же самая причина, по которой вы не можете дважды определить printf-подобную функцию в программе на C. Конечно, printf поддерживает разные аргументы и меняет свое поведение в зависимости от того, какие аргументы присутствуют, но это не является перегрузкой в ​​смысле этого термина в C ++.

person Billy ONeal    schedule 20.06.2011
comment
+1 Хорошая справочная информация; акцентирует внимание на различиях: например, ... позволяет вызывающей стороне изменять количество аргументов, но можно ожидать, что загрузчик ОС всегда будет вызывать main с тем же количеством аргументов. Если программа не перечисляет (int argc, char* argv[]) явно, большинство реализаций все равно будут рассматривать их неявно; регистры и / или стек, в которых они будут находиться, вероятно, загружаются своими значениями до вызова main. К счастью, вы не получаете предупреждений о неиспользуемых переменных :-). Итак, vs printf ... меняет свое поведение, main, вероятно, постоянный (но формально imp. Def.) - person Tony Delroy; 21.06.2011

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

int main(int argc, char **argv) и int main() должны быть предпочтительными сигнатурами для него, но компиляторы могут принять main с другими параметрами.

person peoro    schedule 20.06.2011
comment
Означает ли это, что main всегда объявляется extern "C", независимо от того, пишете ли вы это явно? - person Kerrek SB; 20.06.2011
comment
@iammilind: мне не удалось обнаружить такое требование в стандарте, и я был бы удивлен, если бы он присутствовал, поскольку вы не можете вызывать main напрямую из любого контекста, даже из ОС, поскольку ОС должна вызывать специально сгенерированный статический код инициализации перед основным --ie это деталь реализации, как это искажено или нет, оно может иметь специальные искажения или вообще не искажаться. - person David Rodríguez - dribeas; 20.06.2011
comment
@ Дэвид, я не говорил о стандарте, но говорю, основываясь на наблюдении. Во-первых, имя main() не искажается до тех пор, пока оно не окажется в глобальной области, а во-вторых, когда вы объявляете несколько main() с разными аргументами в одном файле, компилятор выдает ошибку как: error: declaration of C function int main() conflicts with ... - person iammilind; 20.06.2011
comment
@iammilind: Это означает только то, что ваш компилятор на вашей платформе рассматривает main как функцию C, а не то, что в целом он не искажен, поскольку считается функцией C или что он всегда extern "C". В частности, на платформе (ОС), которая вызывала функцию стиля C main в качестве точки входа в программу, компилятор C ++ был бы вынужден преобразовать вашу main функцию во что-то другое и добавить статическую инициализацию к символ _main. Причина, по которой это не указано, заключается в том, что это имеет дело с интерфейсом с ОС, а стандарт C ++ не может предписывать, что там делать. - person David Rodríguez - dribeas; 20.06.2011

Невозможно перегрузить main () в C ++, потому что. компилятор показал следующую ошибку:

error C2731: 'main' : function cannot be overloaded 
person Dheeraj Bansal    schedule 20.06.2011