статическое фиаско порядка инициализации

Я читал о SIOF из книги, и он дал пример:

//file1.cpp
extern int y;
int x=y+1;

//file2.cpp
extern int x;
int y=x+1;  

Теперь Мой вопрос:
В вышеупомянутом коде, после вещей произойдет?

  1. при компиляции file1.cpp, компилятор оставляет y, как это - т.е. не выделяет устройство хранения данных для него.
  2. компилятор выделяет устройство хранения данных для x, но не инициализирует его.
  3. При компиляции file2.cpp, компилятор оставляет x, как это - т.е. не выделяет устройство хранения данных для него.
  4. компилятор выделяет устройство хранения данных для y, но не инициализирует его.
  5. При соединении file1.o и file2.o, теперь позвольте file2.o, инициализируется сначала, так теперь:
    X получает начальное значение 0? или не становится инициализированным?
20
задан frogatto 18 January 2017 в 08:31
поделиться

4 ответа

Шаги инициализации приведены в 3.6.2 «Инициализация нелокальных объектов» стандарта C ++:

Шаг 1: x и y инициализируются нулем перед любой другой инициализацией.

Шаг 2: x или y инициализируется динамически, что не определено стандартом. Эта переменная получит значение 1 , поскольку другая переменная будет инициализирована нулем.

Шаг 3: другая переменная будет динамически инициализирована, получив значение 2 .

12
ответ дан 30 November 2019 в 00:51
поделиться

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

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

Я думаю, что наиболее вероятным сценарием будет:

  1. Место выделено для переменных, и обе имеют значение 0.
  2. Одна переменная, скажем x, инициализируется и устанавливается на значение 1.
  3. Другой, скажем, y, инициализируется и имеет значение 2.

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

1
ответ дан 30 November 2019 в 00:51
поделиться

SIOF в значительной степени является артефактом времени выполнения, компилятор и компоновщик не имеют к нему никакого отношения. Рассмотрим функцию atexit (), она регистрирует функции, которые будут вызываться при выходе из программы. Во многих реализациях CRT есть нечто подобное для инициализации программы, назовем это atinit ().

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

Вот где в игру вступает функция atinit (). Обычная реализация CRT просматривает список указателей на функции atinit и по порядку выполняет фрагменты инициализации. Проблема заключается в порядке регистрации функций в списке atinit (). Хотя atexit () имеет четко определенный порядок LIFO и неявно определяется порядком, в котором код вызывает atexit (), это не относится к функциям atinit. Спецификация языка не требует заказа, вы ничего не можете сделать в своем коде, чтобы указать порядок. SIOF - это результат.

Одна из возможных реализаций - компилятор, выделяющий указатели на функции в отдельном разделе. Компоновщик объединяет их, создавая список atinit. Если ваш компилятор делает это, то порядок инициализации будет определяться порядком, в котором вы связываете объектные файлы. Посмотрите на файл карты, вы должны увидеть раздел atinit, если ваш компилятор делает это. Он не будет называться atinit, но вероятно какое-то имя с «init». Взгляд на исходный код CRT, который вызывает main (), также должен дать представление.

11
ответ дан 30 November 2019 в 00:51
поделиться

Вся суть (и причина, по которой это называется «фиаско») в том, что невозможно сказать с какой-либо уверенностью , что произойдет в таком случае. По сути, вы просите чего-то невозможного (чтобы две переменные были одна больше другой). Поскольку они не могут этого сделать, остается открытым вопрос о том, что они будут делать - они могут выдать 0/1, или 1/0, или 1/2, или 2/1, или, возможно, (в лучшем случае) просто ошибку. сообщение.

2
ответ дан 30 November 2019 в 00:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: