2013-07-22 4 views
24

В 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:
Разъяснение 2 вопроса.

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

Все четыре переменные имеют статический класс хранения. –

+0

@KerrekSB Как «статический класс хранения» относится к моему вопросу? – Zachary

+0

Класс хранения определяет поведение инициализации. –

ответ

21

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

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

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

extern int f(); 

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

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

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

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

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

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

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

+0

Thx James. Ваш ответ действительно замечательный. В последнем абзаце вы упомянули, что динамическая инициализация находится в сегменте .bss. Зачем? Интуитивно я думаю, что он должен быть в сегменте .data, поскольку он инициализирован. – Zachary

+0

Чтобы снова беспокоить вас. Как вы знаете, от вас ответит, я лучше понимаю. Но я не знаю этого. Как были выработаны эти правила языка. Не могли бы вы дать мне несколько ссылок? Вот ссылка [Спецификаторы класса хранения] (http://en.cppreference.com/w/cpp/language/storage_duration). Прочитав эту страницу, я был более смущен. Следует рассмотреть два небольших предмета. – Zachary

+0

@Zack Динамическая инициализация не выполняется до тех пор, пока программа не начнет выполнение. Что касается загрузки исполняемого файла, то он инициализируется нолем, и все. –

1

Перефразировано от стандарта:

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

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

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

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

3

Когда эти четыре переменные инициализированы?

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

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

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

+0

Много thx. Особенно для второго вопроса. Переменная на самом деле является адресным блоком памяти. Таким образом, 5 просто сохраняется в выделенном ему блоке памяти в разделе/​​сегменте .data. – Zachary

+0

Я объяснил это в своем посте по второму вопросу. Майк, вы думаете, что инициализация выполняется во время связи? Поскольку после процесса привязки сегменты программы в основном исправлены! – Zachary

12

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

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

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

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

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

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

Важным моментом является то, что статическая фаза инициализации doens't «запустить» в все. Данные есть с самого начала. Это означает, что нет никакого «заказа» или любого другого такого динамического свойства, которое относится к статической инициализации. Первоначальные значения жестко закодированы в ваш двоичный код программы, если хотите.

Смежные вопросы