Когда инициализируются статические и глобальные переменные?
В 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 динамически инициализируются, поэтому их инициализация выполняется в соответствии с указанным выше правилом.
Что касается вашего второго момента, я не уверен, что понимаю, что вы имеете в виду. Не могли бы вы уточнить?