Я читал часто задаваемые вопросы по C++ и заметил одно предложение.
main() не может быть встроенным.
Почему это?
Я читал часто задаваемые вопросы по C++ и заметил одно предложение.
main() не может быть встроенным.
Почему это?
В С++ недопустимо вызывать основную функцию в вашем коде, поэтому ее нельзя было бы встроить.
*static_cast<int*>(0) = 10
тоже компилируется, и это не значит, что это правильно... как в случае с любым нарушением ODR и многими другими вещами... тот факт, что она компилируется, не означает, что это легальная программа .
- person David Rodríguez - dribeas; 08.08.2011
-pedantic-errors
.
- person sepp2k; 08.08.2011
inline
.
- person Lightness Races in Orbit; 08.08.2011
main()
из main()
, то этот вызов определенно не может быть встроен ... (по крайней мере, не рекурсивно)
- person Chris Lercher; 10.08.2011
Потому что стандарт говорит так:
[2003: 3.6.1/3]
: Функция main не должна использоваться (3.2) в программе. Связь (3.5) main определяется реализацией. Программа, объявляющая main встроенной или статической, имеет неправильный формат. Имя main не зарезервировано для других целей. [Пример: функции-члены, классы и перечисления могут называться основными, как и сущности в других пространствах имен. ]
И почему так сказано? Потому что он пытается оставить как можно больше информации о реализации main
на усмотрение индивидуума... ну, реализации... насколько это возможно, и не хочет ограничивать реализации, требуя, чтобы inline
было действительным здесь, когда это необходимо. вряд ли имеет практическую пользу.
Мой друг в комитете подтвердил это:
Нет никаких причин, по которым
inline
main()
не работали бы сами по себе. [..] У меня мог бы быть интерпретатор C++, который мог бы вызывать встроенныйmain()
. [..] [Но]inline
/static
main()
запрещены, чтобы избежать путаницы. Мне трудно представить, что обоснование может быть чем-то дополнительным к тому, что уже было сказано в [этих вопросах и ответах].
Кстати, не путайте ключевое слово подсказки inline
с фактически встроенными функциями. Вы можете пометить функцию inline
, и она может быть физически не встроена.
Таким образом, даже если верно, что main
"нельзя встроить" (строго говоря, это неправда, хотя встраивание main
было бы довольно неудобным и бессмысленным, как объясняется в других ответах), теоретически это все равно могло бы отлично поддерживает ключевое слово подсказки inline
.
Это не по причине, указанной выше, и в ответе litb: это усложнит ситуацию без реальной пользы.
inline
для main
тривиальна, поскольку ее можно просто игнорировать, следовательно, это не ограничивает какую-либо реализацию, следовательно, эта возможная причина запрета стандарта не выдерживает критики. Извините. но я не могу предложить больше, чем в моем ответе, что нет смысла иметь inline
(и в этом мы согласны, я думаю).
- person Cheers and hth. - Alf; 09.01.2014
main
в нескольких TU, если все определения лексически идентичны (среди других ограничений), что просто не имеет смысла, чтобы его стоило запрещать.
- person Lightness Races in Orbit; 09.01.2014
main
быть функцией означает, что ее можно вызывать из пользовательского кода (за исключением того, что это не разрешено), что ее адрес можно взять (за исключением того, что это не разрешено), что это UB для потока вне конца (за исключением того, что это специально поддерживается и четко определено), что любой вызов должен соответствовать списку формальных аргументов (за исключением того, что на практике один и тот же вызов библиотеки времени выполнения вызывает его независимо от списка формальных аргументов) и так далее. То есть, поскольку main
является очень особенным, обычные последствия легко определяются. Хотя это была хорошая идея. :) Но не получилось. :(
- person Cheers and hth. - Alf; 09.01.2014
main
, которые на самом деле необходимы в существовании.
- person Lightness Races in Orbit; 09.01.2014
main
имеет значение, которое должно взаимодействовать со средой выполнения реализации и с основной операционной системой (поскольку это точка входа в программу), поэтому комитету людей нет смысла слишком много назначать по этому поводу. Напомним, что связывание других функций определяется пользователем, поэтому стандарт является немного ограничивающим main
здесь, говоря: слушайте своего поставщика компилятора, потому что они могут выбирать этот не ты. :)
- person Lightness Races in Orbit; 07.06.2015
Библиотека времени выполнения C должна найти этот символ, чтобы «знать», какую функцию запускать.
call
для функции main()
, и она почти всегда связана динамически. Так что это просто не может работать в типичном случае.
- person whitequark; 08.08.2011
Вы не можете напрямую вызвать main() (это запрещено в C++), поэтому нет смысла встраивать его.
Обычно main()
вызывается из системной init()
функции. Таким образом, необходимо, чтобы для main()
могло быть ровно одно определение.
Теперь, если мы сможем inline
использовать функцию main()
и включить ее в заголовочный файл, тогда для каждой единицы перевода будет свое определение main()
. Что не разрешено. Вы можете объявить main()
в namespace
и inline
в нем. Но не глобальный main()
.
inline
.
- person Lightness Races in Orbit; 08.08.2011
static int main()
тоже имеет неправильный формат :D)
- person Lightness Races in Orbit; 08.08.2011
static int main()
эквивалентно namespace { int main() }
. О чем я рассказал в ответе.
- person iammilind; 08.08.2011
main
, так что вы хотите сказать?
- person Thomas Matthews; 08.08.2011
main()
выбрать?
- person iammilind; 08.08.2011
main
останется в силе. Хотя встроенная версия main
может быть избыточной или бесполезной, я не вижу причин не разрешать ее.
- person Thomas Matthews; 08.08.2011
во-первых, вы должны понять, как работает функция со встроенным
пример:
inline void f() {
int a = 3;
a += 3;
cout << a;
}
int main() {
f();
return 0;
}
будет выглядеть для компилятора как:
int main() {
int a = 3;
a += 3;
cout << a;
return 0;
}
Глядя на этот пример, как вы хотите сделать main встроенным? Этот метод встроен сразу.
inline
d, которая имеет только один вызов, и функции main
, которая имеет только один вызов?
- person Thomas Matthews; 08.08.2011
This method is inline immediately.
Неправда. inline
— это всего лишь подсказка. Он не выполняет встраивание функций.
- person Lightness Races in Orbit; 17.11.2012
В стандарте С++ говорится, что функция main
не может быть встроена, согласно ответу @Tomalak Geret'kal. В этом ответе обсуждается возможность встраивания функции main
, если ограничение в стандарте снято.
Определение Inline
Ключевое слово inline
— это предложение компилятору вставить содержимое функции на место. Одно из намерений состоит в том, чтобы удалить накладные расходы, присутствующие при вызове и возврате из функции (подпрограммы).
Важной ситуацией встраивания является случай, когда есть указатель на функцию. В этом случае должна быть хотя бы одна статическая копия функции. В этом случае компоновщик может разрешить «внешние связи» встроенной функции, потому что существует одна статическая версия.
Важно отметить, что компилятор и компоновщик определяют, следует ли вставлять содержимое или вызывать один экземпляр функции.
Также следует отметить, что функции, которые не помечены программистом, также могут быть встроены компилятором.
Встраивание основной функции
Поскольку разрешен только один вызов main
, как она связана, зависит от компилятора. Отдельные экземпляры встроенных функций разрешены Стандартом. Компилятору разрешено преобразовывать функцию inlined
в вызов функции для одного экземпляра. Таким образом, компилятор проигнорировал бы встроенное предложение для функции main
.
Компилятор и компоновщик должны убедиться, что существует только один экземпляр встроенной функции main
. Здесь начинается сложная часть, особенно с внешней связью. Один из процессов обеспечения одного экземпляра состоит в том, чтобы оставить информацию о том, что перевод имеет «основную» функцию независимо от того, встроен он или нет. Примечание. Когда выполняется вызов встроенной функции, компилятору разрешается удалить функцию из таблиц символов для внешней компоновки, поскольку идея состоит в том, что функция не будет вызываться внешними функциями.
Резюме
Технически ничто не препятствует встраиванию функции main
. Уже существует механизм для преобразования встроенных функций в отдельные экземпляры и для идентификации нескольких экземпляров функции. Когда есть указатель на встроенную функцию, создается единственный экземпляр функции, поэтому у него есть адрес. Этот механизм удовлетворит требованиям библиотеки времени выполнения для main
, имеющего адрес. В случае inline
для функции main
она будет проигнорирована, но не должно быть никаких причин для предотвращения этого синтаксиса (кроме путаницы). Ведь уже есть синтаксические случаи, которые избыточны, например объявление параметра, который передается по значению (копии) как const
.
- Это только мое мнение, я могу ошибаться. -- Деннис Миллер, комик.
Другие отмечают, что вызов main
не может быть осмысленно встроен на уровне машинного кода. Это мусор. Это потребует небольшой помощи от компоновщика (например, глобальной оптимизации) или перекомпиляции части библиотеки времени выполнения для каждого приложения, но это вполне выполнимо, здесь нет технических проблем.
Однако эффект подсказки inline
, заключающийся в том, что вызовы предпочтительно должны быть встроенными, не имеет значения для функции, которая вызывается только один раз и на верхнем уровне управления, как main
.
Единственный гарантированный эффект inline
заключается в том, что функция внешней связи может быть определена (одинаково) в двух или более единицах перевода, т. е. влияет на правило одного определения.
На практике это позволяет поместить определение в заголовочный файл, а его размещение в заголовочном файле также практически необходимо для обеспечения идентичных определений.
Это не имеет смысла для main
, поэтому нет причин для main
быть inline
.
main
было inline
убедительным, но не прямым объяснением того, почему это было сделано так, что оно не может быть помечено inline
.
- person Lightness Races in Orbit; 08.08.2011
main
не идеально. Например, я всегда думал и до сих пор считаю, что после первого утверждения основного бита в корне неверно. Но я нигде не видел, чтобы это обсуждалось. Может быть, это просто мое несовершенное понимание английского...
- person Cheers and hth. - Alf; 08.08.2011
main
, которая при связывании косвенно вызывает ваш код. Априори я не вижу существенной разницы между этим и определением main в заголовке.
- person Tim Seguine; 06.10.2016
main
в заголовок, предназначенный для включения только в одну единицу перевода. На самом деле я так и сделал (пример на github). Но тогда не имеет смысла гарантировать идентичные определения в нескольких единицах перевода. Как я понимаю, никакая другая причина для inline
не применима.
- person Cheers and hth. - Alf; 07.10.2016
Вы можете определить main
только один раз. Таким образом, установка inline
не будет служить никакой цели - inline
имеет важное значение только для функций, которые вы можете определить несколько раз в программе (все определения будут обрабатываться так, как если бы было только одно определение, и все определения должны быть одинаковыми).
Поскольку inline
функции могут быть определены в программе несколько раз, а inline
также служит для максимально быстрого вызова функции, помеченной inline
, Стандарт требует, чтобы inline
функции определялись в каждой единице перевода, в которой он используется. Таким образом, компиляторы обычно отбрасывают определение функции, если оно inline
и функция не использовалась кодом в текущей единице перевода. Делать это для main
было бы совершенно неправильно, что показывает, что inline
и семантика main
совершенно несовместимы.
Обратите внимание, что вопрос в вашем заголовке "Почему main() в C++ не может быть встроен?" и утверждение, которое вы цитируете из Стандарта, касается разных вещей. Вы спрашиваете, может ли функция быть встроена, что обычно понимается как вставка кода вызываемой функции полностью или частично в вызывающую функцию. Просто пометка функции inline
вовсе не означает встраивания этой функции. Это полностью решение компилятора, и, конечно, если вы никогда не вызываете main
(и вы не можете этого сделать), тогда нечего встраивать.
main
быть встроенным потребует этого. Исторически C++ не любил магию. (Но это было до шаблонов.)
- person James Kanze; 09.08.2011
Если вы подключили статически к CRT и включили некоторую компиляцию-встраивание во время компоновки (как в MSVC), возможно, это можно будет встроить.
Но на самом деле это не имеет смысла. Она будет вызвана один раз, и эти накладные расходы на вызов функции практически ничто по сравнению со всем остальным, что делается до выполнения первой строки в main.
...
К тому же, это простой способ заставить символ появляться в вашем исполняемом файле только один раз. :)
Существует ряд основных причин. По сути, main
вызывается из базовой процедуры инициализации среды выполнения и только оттуда. Этот код был (очевидно) скомпилирован, не зная, что ваш main
был встроен. Современные технологии компиляторов позволяют выполнять встраивание через границы модулей, но это расширенная функция, не поддерживаемая многими старыми компиляторами. И, конечно же, преимущества встраивания проявляются только тогда, когда функция вызывается очень часто; по определению main
будет вызываться ровно один раз, ни больше, ни меньше.
Я вижу, что стандарт говорит об этом, но реальный практический ответ был бы таким же простым, как утверждение, что среда выполнения, добавляемая к каждой программе C и C++, должна вызывать некоторую точку в исполняемом файле. Эта функция должна иметь внешний символ (и адрес при выполнении), чтобы компоновщик мог найти ее для вызова в начале выполнения. Следовательно, вы не можете объявить его как inline
, потому что встроенный компилятор не сгенерирует для него внешний символ.
inline
не обязательно приводит к тому, что функция становится встроенной.
- person Lightness Races in Orbit; 17.11.2012
inline
имеет внешнюю связь, если только она не является функцией области видимости пространства имен, явно объявленной static
.
- person Cheers and hth. - Alf; 07.10.2016
Поскольку это функция main(), которая запускает выполнение, когда код компилируется в двоичный, все находится в самом main()
. так что можно сказать, он уже встроен!
И да, использование inline для вашей программы на C++ незаконно, это больше касается синтаксиса!
Для большинства комбинаций компилятор/архитектура функция main()
в исходном коде становится достаточно нормальной функцией в конечном бинарном файле. Это только потому, что это удобно на этих архитектурах, а не потому, что стандарт говорит, что так должно быть.
В архитектурах с ограниченной памятью многие компиляторы, которые создают плоский двоичный файл (например, шестнадцатеричный формат intex) вместо контейнера, удобного для динамического компоновщика (например, elf или xcoff), оптимизируют весь шаблон, поскольку он будет просто раздуваться. Некоторые архитектуры вообще не поддерживают вызовы функций (на этих платформах возможно только ограниченное подмножество C++).
Чтобы поддерживать самое большое разнообразие таких архитектур и сред сборки, стандартные выборы сохраняют семантику main()
максимально открытой, чтобы компилятор мог делать то, что подходит для самых разных платформ. Это означает, что многие функции, доступные в языке в целом, не могут применяться к запуску и завершению работы самого приложения.
Если вам нужно что-то вроде встроенного main()
(или повторного входа, или любой другой необычной функции), вы, конечно, можете вызвать основную функцию как-то иначе:
inline int myMain(int argc, char **argv) { /* whatever */ }
int main(int argc, char **argv) { return myMain(argc, argv); }
По умолчанию встроенные функции имеют статическую область видимости. Это означает, что если мы объявим функцию main() как встроенную, ее область действия будет ограничена файлом, в котором она определена. Тем не менее, стартовая библиотека C (предоставляемая поставщиком компилятора) требует, чтобы «main» был глобальным символом. Некоторые компиляторы позволяют изменять функцию точки входа (например, main) с помощью флагов компоновщика.
встроенные функции обычно не имеют адреса, поэтому нет переносимого способа вызова main, main() нужен адрес, на который может перейти код инициализации. Встроенные функции должны быть встроены в вызывающую функцию, если main встроена, она должна быть встроена в код инициализации программы, который также не является переносимым.
inline
.
- person Flexo; 17.09.2011
операционная система загружает двоичные данные в память; ищет точку входа (символ main в c/c++); делает дальний переход к адресу метки точки входа. Операционная система ничего не знает о функции main в вашем коде, пока программа не загружена.
main
. Вместо этого ОС вызывает точку входа для программы на уровне машинного кода. Для C и C++ эта точка входа обычно является функцией в библиотеке времени выполнения, которая, в свою очередь, выполняет различные операции по инициализации, затем вызывает main
и, наконец, выполняет очистку (например, вызывает установленные обработчики выхода) и завершает работу.
- person Cheers and hth. - Alf; 08.08.2011
main
была скомпилирована в нее. Итак, ответ в том, что вы не можете перекомпилировать свою ОС? - person Kieren Johnstone   schedule 08.08.2011inline
(что, помните, всего лишь намек!). - person Lightness Races in Orbit   schedule 08.08.2011