Я читал часто задаваемые вопросы по С++, и я заметил одно предложение.
main() не может быть встроенным.
Почему это?
Я читал часто задаваемые вопросы по С++, и я заметил одно предложение.
main() не может быть встроенным.
Почему это?
В С++ нецелесообразно вызывать основную функцию в вашем коде, поэтому не было бы никакого отношения к ней.
Поскольку стандарт говорит так:
[2003: 3.6.1/3]
: Функция main не должна использоваться (3.2) внутри программы. связь (3.5) main определяется реализацией. Программа, которая объявляет, что основной является встроенным или статическим, плохо сформирован. Основное название иначе не зарезервированы. [Пример: функции-члены, классы и перечисления можно назвать главными, а также сущностями в других пространствах имен. ]
И почему он так говорит? Потому что он пытается оставить как можно больше о реализации main
для индивидуума.. ну, реализация.. как это возможно, и не хочет ограничивать реализацию, требуя, чтобы inline
был действительным здесь, когда он, возможно, не имеет практическая польза.
Мой друг в комитете подтвердил это:
Нет причин, по которым
inline
main()
не будет работать сам по себе. [..] Я мог бы использовать интерпретатор С++, который может вызывать inlinedmain()
. [..] [Но]inline
/static
main()
запрещены, чтобы надеяться избежать путаницы. Мне трудно представить, что обоснование было бы чем-то дополнительным к тому, что уже было сказано в [этом Q & A].
Кстати, не путайте ключевое слово inline
hint с фактически встроенными функциями. Вы можете отметить функцию inline
, и она не может быть физически встроена.
Итак, даже если это правда, что main
"не может быть встроено" (и, строго говоря, это неверно, хотя вложение main
было бы довольно неудобным и бессмысленным, как объяснялось в других ответах), теоретически он мог бы поддерживайте ключевое слово подсказки inline
просто отлично.
Это не по причине, о которой говорилось выше, и в литвом ответе: это осложнит ситуацию без реальной выгоды.
Библиотека времени выполнения C должна найти этот символ, чтобы "знать", какую функцию запускать.
Вы не можете напрямую вызвать main() (это запрещено в С++), поэтому нет смысла его встраивать.
Обычно main()
вызывается из системных функций init()
. Таким образом, для main()
требуется ровно одно определение.
Теперь, если мы можем inline
использовать функцию main()
и включить в файл заголовка, то для каждой единицы перевода будет другое определение для main()
. Это недопустимо. Вы можете объявить main()
в namespace
и inline
. Но не глобальный main()
.
во-первых, вы должны понять, как работает функция с встроенным
Пример:
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
, что вызовы должны быть предпочтительно встроены, не имеет значения для функции, которая вызывается только один раз и на верхнем уровне управления, поскольку main
.
Единственный гарантированный эффект inline
заключается в том, чтобы позволить определять внешнюю функцию привязки (идентично) в двух или более единицах перевода, т.е. влияя на правило одной четкости.
В практическом плане это позволяет помещать определение в файл заголовка и помещать его в файл заголовка также практически необходимо для обеспечения идентичных определений.
Это не имеет смысла для main
, поэтому нет причин для main
быть inline
.
В стандарте С++ указано, что функция main
не может быть встроена, в ответ @Tomalak Geret'kal. В этом ответе обсуждается возможность вложения функции main
, было ли ограничение в стандартном удалении.
Определение Inline
Ключевое слово inline
- это предложение компилятору вставить содержимое функции in-situ. Одно из намерений - удалить накладные расходы при вызове и возврате из функции (подпрограммы).
Важной ситуацией вложения является случай, когда имеется указатель на функцию. В этом случае должна быть хотя бы одна статическая копия функции. В этом случае компоновщик может разрешить "внешние связи" встроенной функции, поскольку существует одна статическая версия.
Важно отметить, что компилятор и компоновщик определяют, следует ли вставлять содержимое или вызывать один экземпляр функции.
Также следует отметить, что функции, которые не помечены программником, также могут быть встроены компилятором.
Вложение основной функции
Поскольку допускается только один вызов main
, , как он связан с компилятором. Стандартными могут быть отдельные экземпляры встроенных функций. Компилятору разрешено преобразовывать функцию inlined
в вызов функции для одного экземпляра. Таким образом, компилятор игнорирует встроенное предложение для функции main
.
Компилятор и компоновщик должны убедиться, что существует только один экземпляр встроенной функции main
. Это, где сложная часть приходит, особенно с внешней связью. Один процесс для обеспечения одного экземпляра - оставить информацию о том, что перевод имеет "основную" функцию независимо от того, является ли она встроенной. Примечание. Когда выполняется вызов встроенной функции, компилятору разрешено удалять функцию из таблиц символов для внешней привязки, поскольку идея состоит в том, что функция не будет вызываться внешними функциями.
Резюме
Технически нет ничего, что предотвращало бы включение функции main
. Механизм уже существует для преобразования встроенных функций в отдельные экземпляры и для идентификации нескольких экземпляров функции. Когда есть указатель на встроенную функцию, создается один экземпляр функции, поэтому он имеет адрес. Этот механизм удовлетворяет требованиям библиотеки времени выполнения для main
с адресом. В случае inline
для функции main
он будет проигнорирован, но не должно быть никаких оснований для предотвращения этого синтаксиса (за исключением путаных людей). В конце концов, уже есть случаи синтаксиса, которые являются избыточными, например объявление параметра, который передается значением (копией) как const
.
"Это только мое мнение, я могу ошибаться". - Деннис Миллер, комик.
Вы можете определить только main
один раз. Поэтому ставить inline
не будет никакой цели - inline
имеет только значительную цель для функций, которые вы можете определить несколько раз в программе (все определения будут обрабатываться так, как если бы было только одно определение, и все определения должны быть то же самое).
Поскольку функции inline
могут быть определены несколько раз в программе, а inline
также служит для быстрого выполнения вызовов inline
-маркированной функции, Стандарт требует функций inline
определенный в каждой единицы перевода, в которой он используется. Поэтому компиляторы обычно отбрасывают определение функции, если она inline
, и эта функция не использовалась кодом в текущем блоке перевода. Сделать это для main
было бы совершенно неправильно, что показывает, что inline
и семантика main
полностью несовместимы.
Обратите внимание, что вопрос в заголовке "Почему main() на С++ не может быть встроен?" и выражение, которое вы цитируете из Стандарта, касается разных вещей. Вы спрашиваете, может ли функция быть встроенной, что обычно понимается как полностью или частично вставить код вызываемой функции в вызывающую функцию. Простое обозначение функции inline
не подразумевает включение этой функции вообще. Это полностью решение компилятора, и, конечно, если вы никогда не назовете main
(и вы не можете этого сделать), то нечего встраивать.
Если вы связали статически с CRT и включили некоторую компоновку-вложения link-time (например, MSVC), возможно было бы встроить его.
Но это не имеет смысла. Он будет вызываться один раз, и этот вызов функции-функции практически ничтожен по сравнению со всем остальным, что выполняется до выполнения первой строки в главном.
...
Aaand, это простой способ заставить символ появляться только один раз в вашем исполняемом файле.:)
Существует ряд основных причин. В принципе, main
вызывается из
основной инициализационной процедуры выполнения, и только оттуда.
Этот код был (очевидно) скомпилирован, не зная, что ваш main
был
встраиваемый. Современная технология компилятора способна встраивать
границ модуля, но это расширенная функция, не поддерживаемая многими
более старых компиляторов. И, конечно же, преимущества inlining
присутствует, когда функция вызывается очень часто; по определению, main
будет называться ровно один раз, не более, не меньше.
Я вижу, что стандарт говорит так, но реальный практический ответ был бы таким же простым, как заявить, что среда выполнения, добавленная к каждой программе на C и С++, должна вызывать в какой-то момент исполняемого файла. Эта функция должна иметь внешний символ (и адрес при запуске), чтобы компоновщик мог найти его для вызова в начале выполнения. Следовательно, вы не можете объявить его как inline
, потому что встроенный компилятор не генерирует для него внешний символ.
Поскольку его основная() функция, которая запускает выполнение, когда код скомпилируется в двоичный файл, все находится в main()
. так что вы можете сказать, что он уже встроен!
И да, это незаконно использовать inline для вашей C + + программы, что больше о синтаксисе!
Для большинства комбинаций компилятора/архетекции функция main()
в источнике становится разумно нормальной функцией в финальном двоичном файле. Это связано только с тем, что это удобно для этих археологов, а не потому, что стандарт говорит, что это так.
В ограниченных арсеналах памяти многие компиляторы, которые производят плоский двоичный код (например, intex hex format) вместо динамического компоновщика, совместимого с контейнером (например, эльфа или xcoff), оптимизируют весь шаблонный шаблон, поскольку он просто раздувается, Некоторые архитектуры вообще не поддерживают вызовы функций (на этих платформах возможно только ограниченное подмножество С++).
Для поддержки самого широкого разнообразия таких архитектур и построительных сред стандартная выборка сохраняет семантику main()
как можно более открытой, так что компилятор может делать то, что право для самых разных платформ. Это означает, что многие функции, доступные на языке в целом, не могут применяться к запуску и завершению самого приложения.
Если вам нужно что-то вроде встроенного main()
(или реентерации или любой причудливой функции), вы можете, конечно, вызвать основную функцию:
inline int myMain(int argc, char **argv) { /* whatever */ }
int main(int argc, char **argv) { return myMain(argc, argv); }
Встроенные функции имеют статический объем по умолчанию. Это означает, что если мы объявим main() как inline, то область действия будет ограничена файлом, в котором она определена. Тем не менее, библиотека запуска C (предоставляемая поставщиком компилятора) нуждается в "главном", чтобы быть глобальным символом. Существуют некоторые компиляторы, которые позволяют изменять функцию точки входа (например, main) с использованием флагов компоновщика.
встроенные функции обычно не имеют адреса, поэтому нет портативного способа вызова main, main() нуждается в адресе, на который может перейти код init. Вложенные функции предназначены для застревания в вызывающей функции, если основной является встроенным, он должен быть встроен в код инициализации программы, который также не переносится.
загружает двоичные данные в память; ищет точку входа ( "главный" символ в c/С++); делает далеко идущий переход к addres метки точки входа. Операционная система ничего не знает о главной функции вашего кода, пока программа не будет загружена.