Когда инициализируются статические и глобальные переменные?

В C++ Я знаю, что объекты static и global создаются перед функцией main. Но, как вы знаете, в C такого типа initialization procedure до main нет.

Например, в моем коде:

int global_int1 = 5;
int global_int2;
static int static_int1 = 4;
static int static_int2;
  • Когда эти четыре переменные инициализированы?
  • Где значения для инициализации, такие как 5 и 4, сохраняются во время компиляции? Как управлять ими при инициализации?

EDIT:
Уточнение второго вопроса.

  • В моем коде я использую 5 для initialize global_int1, так как компилятор назначает 5 на global_int? Например, возможно, компилятор сначала сохранит значение 5 где-нибудь (т.е. Таблицу) и получит это значение при начале инициализации.
  • Что касается "Как управлять ими при инициализации?", это очень неопределенно, и я сам не понимаю, как интерпретировать. Иногда нелегко объяснить вопрос. Остерегайтесь этого, так как я еще не полностью изучил этот вопрос.

Ответ 1

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

Формально С++ инициализирует такие переменные в три этапа: 1. Нулевая инициализация 2. Статическая инициализация 3. Динамическая инициализация Язык также различает переменные, которые требуют динамическая инициализация и те, которые требуют статического инициализация: все статические объекты (объекты со статическими время жизни) сначала инициализируются нулем, тогда объекты со статическими инициализация инициализируется, а затем динамическая инициализация имеет место.

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

extern int f();

int g1 = 42;    //  static initialization
int g2 = f();   //  dynamic initialization

Еще одно приближение будет состоять в том, что статическая инициализация что поддерживает C (для переменных со статическим временем жизни), динамическое все остальное.

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

<Дл > <Дт > текстдт > <Дд > Код, загруженный в защищенную от записи область. статический переменные с типами `const` также будут размещены здесь. Дд > <Дт > Данные:дт > <Дд > Статические переменные со статическими инициализаторами. Дд > <Дт > ПБС:дт > <Дд > Статические переменные без инициализатора (C и С++) или с динамическими инициализация (С++). Исполняемый файл не содержит изображения для этого сегмент, и система просто устанавливает все значение `0` перед начиная ваш код. Дд > Дл >

Я подозреваю, что многие современные системы все еще используют что-то аналогично.

ИЗМЕНИТЬ:

Еще одно замечание: вышеупомянутое относится к С++ 03. Для существующих программ, С++ 11, вероятно, ничего не меняет, но он add constexpr (что означает, что некоторые пользовательские функции все еще может быть статической инициализацией) и локальные переменные потока, который открывает совершенно новую банку червей.

Ответ 2

Предисловие: слово "статический" имеет огромное количество различных значений в С++. Не путайте.

Все ваши объекты имеют статическую продолжительность хранения. Это потому, что они не являются ни автоматическими, ни динамическими. (Nor thread-local, хотя thread-local немного напоминает статическую.)

В С++ статические объекты инициализируются в две фазы: статическая инициализация и динамическая инициализация.

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

  • Статическая инициализация - это когда инициализатор известен статически и никакой конструктор не должен запускаться. (Статическая инициализация - либо инициализация нуля, либо инициализация константы.) Это относится к вашим переменным int с постоянным инициализатором, и вам гарантировано, что они действительно инициализированы в статической фазе.

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

Важнейшим моментом является то, что статическая фаза инициализации вообще не выполняется. Данные есть с самого начала. Это означает, что нет никакого "заказа" или любого другого такого динамического свойства, которое относится к статической инициализации. Начальные значения жестко закодированы в двоичном коде программы, если вы это сделаете.

Ответ 3

Когда эти четыре переменные инициализируются?

Как вы говорите, это происходит до запуска программы, т.е. до начала main. C не уточняет это; в С++ это происходит во время статической фазы инициализации перед объектами с более сложными конструкторами или инициализаторами.

Где значения для инициализации, такие как 5 и 4, сохраняются во время компиляции?

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

Ответ 4

Парафраз из стандарта:

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

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

Итак, в вашем коде global_int1 и static_int1 определенно инициализируются перед первым оператором в основном, потому что они статически инициализируются. Однако global_int2 и static_int2 динамически инициализируются, поэтому их инициализация выполняется в соответствии с указанным выше правилом.

Что касается вашего второго момента, я не уверен, что понимаю, что вы имеете в виду. Не могли бы вы уточнить?