Является ли int main действительной программой на C / C ++?

Я спрашиваю, потому что мой компилятор, кажется, так думает, хотя я не думаю.

echo 'int main;' | cc -x c - -Wall
echo 'int main;' | c++ -x c++ - -Wall

Clang не выдает ни предупреждения, ни ошибки, а gcc выдает только кроткое предупреждение: 'main' is usually a function [-Wmain], но только при компиляции как C. Указание -std= не имеет значения.

В противном случае он компилируется и ссылки нормально. Но при исполнении он сразу заканчивается SIGBUS (для меня).

Прочитав (отличные) ответы на Что должно возвращать main () в C и C ++? и быстрый поиск по языковым спецификациям, это, безусловно, казаться для меня это главное функция необходимо. Но словоблудие от GCC’s -Wmain («Основным» является обычно функция) (и недостаток ошибок здесь), возможно, предполагает иное.

Но почему? Есть ли какой-то странный крайний случай или «историческое» использование для этого? Кто-нибудь знает, что дает?

Я полагаю, что я действительно считаю, что это должно быть ошибка в размещенной среде, а?

111

Решение

Поскольку вопрос дважды помечен как C и C ++, причины для C ++ и C будут другими:

  • C ++ использует искажение имен, чтобы помочь компоновщику различать текстуально идентичные символы разных типов, например глобальная переменная xyz и отдельно стоящая глобальная функция xyz(int), Тем не менее, имя main никогда не покалечен
  • C не использует искажение, поэтому программа может перепутать компоновщик, предоставив символ одного вида вместо другого символа, и программа успешно установит связь.

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

Вот еще одна иллюстрация того же вопроса:

файл x.c:

#include <stdio.h>
int foo(); // <<== main() expects this
int main(){
printf("%p\n", (void*)&foo);
return 0;
}

файл y.c:

int foo; // <<== external definition supplies a symbol of a wrong kind

компилирования:

gcc x.c y.c

Он компилируется и, вероятно, будет работать, но это неопределенное поведение, потому что тип символа, обещанный компилятору, отличается от фактического символа, передаваемого компоновщику.

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

97

Другие решения

main не является зарезервированное слово это просто предопределенный идентификатор (лайк cin, endl, npos…), чтобы вы могли объявить переменную с именем main, инициализировать его, а затем распечатать его значение.

Конечно:

  • предупреждение полезно, так как оно весьма подвержено ошибкам;
  • Вы можете иметь исходный файл без main() функция (библиотеки).

РЕДАКТИРОВАТЬ

Некоторые ссылки:

  • main не является зарезервированным словом (C ++ 11):

    Функция main не должны использоваться в программе. Связь
    (3.5) из main определяется реализацией. Программа, которая определяет основные
    как удаленный или который объявляет главное inline, static, или же
    constexpr плохо сформирован. Имя main не иначе
    зарезервированный. [Пример: функции-члены, классы и перечисления могут быть
    называется main, так же как и объекты в других пространствах имен. — конец примера]

    C ++ 11 — [basic.start.main] 3.6.1.3

    [2.11 / 3] […] некоторые идентификаторы зарезервированы для использования реализациями C ++ и стандартными библиотеками (17.6.4.3.2) и не должны использоваться иначе; Диагностика не требуется.

    [17.6.4.3.2 / 1] Определенные наборы имен и сигнатур функций всегда зарезервированы для реализации:

    • Каждое имя, которое содержит двойное подчеркивание __ или начинается с подчеркивания, за которым следует заглавная буква (2.12), зарезервировано для реализации для любого использования.
    • Каждое имя, которое начинается со знака подчеркивания, зарезервировано для реализации для использования в качестве имени в глобальном пространстве имен.
  • Зарезервированные слова в языках программирования.

    Зарезервированные слова не могут быть переопределены программистом, но предопределенные часто могут быть переопределены в некотором качестве. Это случай main: есть области, в которых объявление, использующее этот идентификатор, переопределяет свое значение.

30

Является int main; действительная программа C / C ++?

Не совсем понятно, что такое программа на C / C ++.

Является int main; действительная программа на C?

Да. Автономная реализация может принимать такую ​​программу. main не должно иметь никакого особого значения в автономной среде.

это не действителен в размещенной среде.

Является int main; действительная программа на C ++?

То же самое.

Почему это терпит крах?

Программа не должна иметь смысла в ваш среда. В автономной среде запуск и завершение программы, а также значение main, определены реализацией.

Почему компилятор предупреждает меня?

Компилятор может предупредить вас обо всем, что пожелает, если он не отклоняет соответствующие программы. С другой стороны, предупреждение — это все, что требуется для диагностики несоответствующей программы. Поскольку этот модуль перевода не может быть частью действующей размещенной программы, диагностическое сообщение оправдано.

Является gcc автономная среда или размещенная среда?

Да.

gcc документы -ffreestanding флаг компиляции. Добавьте его, и предупреждение исчезнет. Вы можете использовать его при строительстве, например, ядра или прошивка.

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

19

Это предупреждение, так как оно технически не запрещено. Код запуска будет использовать расположение символа «main» и переходить к нему с тремя стандартными аргументами (argc, argv и envp). Это не так, и во время соединения не может проверить, что это на самом деле функция, и даже что у нее есть эти аргументы. Это также, почему int main (int argc, char ** argv) работает — компилятор не знает об аргументе envp, и он просто не используется, и это очистка вызывающей стороны.

В шутку, вы могли бы сделать что-то вроде

int main = 0xCBCBCBCB;

на компьютере с архитектурой x86 и, игнорируя предупреждения и тому подобное, он не только компилируется, но и фактически работает.

Кто-то использовал метод, подобный этому, чтобы написать исполняемый файл (своего рода), который работает на нескольких архитектурах напрямую — http://phrack.org/issues/57/17.html#article . Это также использовалось, чтобы выиграть IOCCC — http://www.ioccc.org/1984/mullender/mullender.c .

17

Это действительная программа?

Нет.

Это не программа, так как она не имеет исполняемых частей.

Это действительно для компиляции?

Да.

Можно ли использовать с действующей программой?

Да.

Не весь скомпилированный код должен быть исполняемым, чтобы быть действительным. Примерами являются статические и динамические библиотеки.

Вы эффективно создали объектный файл. Это не допустимый исполняемый файл, однако другая программа может ссылаться на объект main в результирующий файл, загрузив его во время выполнения.

Должно ли это быть ошибкой?

Традиционно C ++ позволяет пользователю делать то, что может показаться ему непригодным для использования, но которое соответствует синтаксису языка.

Я имею в виду, что конечно, это может быть классифицировано как ошибка, но почему? Какой цели это послужит тому, что предупреждение не выполняет?

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

9

Я хотел бы добавить к ответам, уже приведенным, со ссылкой на фактические стандарты языка.

Является ли int main; допустимой программой на C?

Краткий ответ (мое мнение): только если ваша реализация использует «автономную среду выполнения».

Все последующие цитаты из C11

5. Окружающая среда

Реализация переводит исходные файлы C и выполняет С программы в
две среды системы обработки данных, которые будут называться
среда перевода и среда исполнения […]

5.1.2 Среды исполнения

Определены две среды исполнения: автономная и размещенная. В
в обоих случаях запуск программы происходит, когда назначенная функция C
вызывается средой исполнения.

5.1.2.1 Отдельно стоящая среда

В автономной среде (в которой выполнение программы на С может занять
место без какой-либо выгоды операционной системы), название и тип
функции, вызываемой при запуске программы, определяются реализацией.

5.1.2.2 Хостинговая среда

Хостинговая среда не обязательна, но должна соответствовать
следующие спецификации, если таковые имеются.

5.1.2.2.1 Запуск программы

Функция, вызываемая при запуске программы, называется главный. […] Это должно
быть определены с типом возврата int и без параметров […] или
с двумя параметрами […] или эквивалентными или другими
определяемый реализацией способ.

Из них наблюдается следующее:

  • Программа C11 может иметь автономную или размещенную среду выполнения и быть действительной.
  • Если он имеет автономный, не должно быть основной функции.
  • В противном случае должен быть один с возвращаемым vale типа ИНТ.

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

Является ли int main; допустимой программой на C ++?

Краткий ответ (мое мнение): только если ваша реализация использует «автономную среду выполнения».

Цитата из C ++ 14

3.6.1 Основная функция

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

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

Опять же, я бы сказал, что для размещенного случая ваш код не является допустимой программой на C ++ 14, но я уверен, что это для отдельного случая.

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

6

Полагаю, я считаю, что я действительно считаю, что это должно быть ошибкой в ​​размещенной среде, а?

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

Предположим, у вас есть модуль компиляции, который определяет глобальную переменную с именем main, Это вполне может быть законным в автономной среде, потому что то, что составляет программу, оставлено на усмотрение реализации в автономной среде.

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

Все хорошо, если вы используете только первый модуль компиляции в автономной среде и только второй в размещенной среде. Что делать, если вы используете оба в одной программе? В C ++ вы нарушили одно правило определения. Это неопределенное поведение. В C вы нарушили правило, согласно которому все ссылки на один символ должны быть согласованными; если это не так, это неопределенное поведение. Неопределенное поведение — это «выйти из тюрьмы, бесплатно!» карточка для разработчиков реализации. Все, что реализация делает в ответ на неопределенное поведение, соответствует стандарту. Реализация не должна предупреждать о, не говоря уже об обнаружении, неопределенного поведения.

Что если вы используете только один из этих модулей компиляции, но вы используете неправильный (что вы и сделали)? В С ситуация ясна. Неспособность определить функцию main в одной из двух стандартных форм в размещенной среде неопределенное поведение. Предположим, вы не определили main совсем. Компилятор / компоновщик не должен ничего говорить об этой ошибке. То, что они жалуются, — приятная вещь от их имени. То, что программа C скомпилирована и скомпонована без ошибок, является вашей ошибкой, а не компилятором.

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

4

Для C это пока поведение, определяемое реализацией.

Как говорится в ISO / IEC9899:

5.1.2.2.1 Запуск программы

1 Функция, вызываемая при запуске программы, называется основной. Реализация заявляет нет
прототип для этой функции. Он должен быть определен с типом возврата int и без
параметры:

int main(void) { /* ... */ }

или с двумя параметрами (называемыми здесь как argc и argv, хотя любые имена могут быть
используется, поскольку они являются локальными для функции, в которой они объявлены):

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

или эквивалент; или каким-либо другим способом, определяемым реализацией.

4
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector