Является ли main () действительно началом программы на C ++? - PullRequest
130 голосов
/ 24 января 2011

Чтение раздела $ 3.6.1 / 1 из стандарта C ++,

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

Теперь рассмотрим этот код,

int square(int i) { return i*i; }
int user_main()
{ 
    for ( int i = 0 ; i < 10 ; ++i )
           std::cout << square(i) << endl;
    return 0;
}
int main_ret= user_main();
int main() 
{
        return main_ret;
}

Этот пример кода делает то, что я намереваюсь сделать, то есть печатать квадрат целых чисел от 0 до 9, до входа в функцию main(), которая должна быть "началом" программа.

Я также скомпилировал его с опцией -pedantic, GCC 4.5.0. Это не дает никакой ошибки, даже предупреждение!

Итак, мой вопрос,

Действительно ли этот код соответствует стандарту?

Если он соответствует стандарту, то не отменяет ли он то, что говорит Стандарт? main() не запуск этой программы! user_main() выполнено до main().

Я понимаю, что для инициализации глобальной переменной main_ret сначала выполняется use_main(), но это совсем другое; Дело в том, что делает недействительным цитируемый оператор $ 3.6.1 / 1 из Стандарта, поскольку main() НЕ является началом программы; на самом деле это end из этой программы!


EDIT:

Как вы определяете слово «старт»?

Это сводится к определению фразы «начало программы» . Так как именно вы это определили?

Ответы [ 11 ]

87 голосов
/ 24 января 2011

Вы неправильно читаете предложение.

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

Стандарт определяет слово «старт» для целей оставшейся части стандарта. Это не говорит о том, что ни один код не выполняется до вызова main. В нем говорится, что запуск программы считается при функции main.

Ваша программа соответствует требованиям. Ваша программа не "запустилась", пока не запустится main. Конструктор вызывается до того, как ваша программа «запускается» в соответствии с определением «запуска» в стандарте, но это вряд ли имеет значение. МНОГО кода выполняется до того, как main будет когда-либо вызываться в каждой программе, а не только в этом примере.

В целях обсуждения ваш код конструктора выполняется до «запуска» программы, и это полностью соответствует стандарту.

82 голосов
/ 24 января 2011

Нет, C ++ делает много вещей для "установки среды" перед вызовом main;однако main является официальным запуском «указанной пользователем» части программы на C ++.

Некоторые настройки среды не контролируются (например, исходный код для установки std :: cout; однако некоторые изсреда является управляемой, как статические глобальные блоки (для инициализации статических глобальных переменных). Обратите внимание, что, поскольку у вас нет полного контроля перед основным, у вас нет полного контроля над порядком, в котором статические блоки инициализируются.

После main ваш код концептуально «полностью контролирует» программу, в том смысле, что вы можете указывать как выполняемые инструкции, так и порядок их выполнения. Многопоточность может изменить порядок выполнения кода; но вы все еще контролируете C ++, поскольку указали, что разделы кода выполняются (возможно) не по порядку.

23 голосов
/ 24 января 2011

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

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

Посмотрите на это:

class Foo
{
public:
   Foo();

 // other stuff
};

Foo foo;

int main()
{
}

Поток вашей программы будет эффективно происходить из Foo::Foo()

15 голосов
/ 24 января 2011

Вы также пометили вопрос как «C», тогда, строго говоря о C, ваша инициализация должна завершиться неудачно в соответствии с разделом 6.7.8 «Инициализация» стандарта ISO C99.

Наиболее актуальным в этом случае представляется ограничение № 4, которое гласит:

Все выражения в инициализаторе для объекта, который имеет статическую длительность хранения, должны быть константными выражениями или строковыми литералами.

Итак, ответ на ваш вопрос заключается в том, что код не соответствует стандарту C.

Возможно, вы захотите удалить тег "C", если вас интересует только стандарт C ++.

10 голосов
/ 24 января 2011

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

9 голосов
/ 24 января 2011

Компилятору часто приходится добавлять код перед main (), чтобы соответствовал стандарту . Поскольку в стандарте указано, что инициализация глобалов / статик должна выполняться до , программа выполняется. И, как уже упоминалось, то же самое касается конструкторов объектов, размещенных в области видимости файла (глобальные переменные).

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

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

Редактировать: см., Например, ISO 9899: 1999 5.1.2:

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

Теория того, как это «волшебство» должно было быть сделано, восходит к рождению Си, когда он был языком программирования, предназначенным для использования только для ОС UNIX на компьютерах с ОЗУ. Теоретически, программа сможет загружать все предварительно инициализированные данные из исполняемого файла в ОЗУ одновременно с загрузкой самой программы в ОЗУ.

С тех пор компьютеры и ОС эволюционировали, и C используется в гораздо более широкой области, чем первоначально предполагалось. Современная ОС ПК имеет виртуальные адреса и т. Д., И все встроенные системы выполняют код из ПЗУ, а не из ОЗУ. Таким образом, существует много ситуаций, когда ОЗУ не может быть установлено «автоматически».

Кроме того, стандарт слишком абстрактен, чтобы что-либо знать о стеках, памяти процесса и т. Д. Эти вещи также должны быть выполнены до запуска программы.

Следовательно, почти каждая программа на C / C ++ имеет некоторый код init / "copy-down", который выполняется перед вызовом main для соответствия правилам инициализации стандартов.

В качестве примера, встроенные системы обычно имеют опцию, называемую «запуск, не совместимый с ISO», при котором весь этап инициализации пропускается по соображениям производительности, а затем код фактически запускается непосредственно из main. Но такие системы не соответствуют стандартам, так как нельзя полагаться на значения инициализации глобальных / статических переменных.

4 голосов
/ 24 января 2011

Ваша "программа" просто возвращает значение из глобальной переменной. Все остальное - код инициализации. Таким образом, стандарт выполняется - у вас просто очень простая программа и более сложная инициализация.

4 голосов
/ 24 января 2011

main () - это пользовательская функция, вызываемая библиотекой времени выполнения C.

см. Также: Избегание основного (точки входа) в программе на C

2 голосов
/ 27 июня 2014

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

1 голос
/ 25 января 2011

main вызывается после инициализации всех глобальных переменных.

Стандарт не указывает порядок инициализации всех глобальных переменных всех модулей и статически связанных библиотек.

...