Является ли main() действительно началом программы на С++?

В разделе $3.6.1/1 из стандарта С++ читается

Программа должна содержать глобальную функция 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(), которая должна быть "началом" программы.

Посмотрите на вывод здесь: http://www.ideone.com/Niy0R

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

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

Является ли этот код действительно стандартным?

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

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


EDIT:

Как вы определяете слово "start"?

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

Ответ 1

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

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

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

Ответ 2

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

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

Стандартом является ОПРЕДЕЛЕНИЕ слова "начало" для целей остальной части стандарта. Он не говорит, что код не выполняется до вызова main. В нем говорится, что начало программы считается функцией main.

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

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

Ответ 3

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

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

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

class Foo
{
public:
   Foo();

 // other stuff
};

Foo foo;

int main()
{
}

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

Ответ 4

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

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

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

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

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

Ответ 5

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

Ответ 6

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

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

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

Изменить: см., например, ISO 9899: 1999 5.1.2:

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

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

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

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

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

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

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

Ответ 11

Да, main - это "точка входа" для каждой программы на С++, за исключением расширений для конкретной реализации. Тем не менее, некоторые вещи происходят до основной, особенно глобальной инициализации, например, для main_ret.