SIOF - это очень большой артефакт времени выполнения, компилятор и компоновщик не имеют к нему никакого отношения.Рассмотрим функцию atexit (), она регистрирует функции, вызываемые при выходе из программы.Многие реализации CRT имеют нечто подобное для инициализации программы, назовем это atinit ().
Инициализация этих глобальных переменных требует выполнения кода, значение не может быть определено компилятором.Таким образом, компилятор генерирует фрагменты машинного кода, которые выполняют выражение, и присваивает значение.Эти фрагменты должны быть выполнены до запуска main ().
Вот где atinit () вступает в игру.Обычная реализация CRT просматривает список указателей на функции atinit и выполняет фрагменты инициализации по порядку.Проблема заключается в порядке, в котором функции зарегистрированы в списке atinit ().Хотя atexit () имеет четко определенный порядок LIFO и неявно определяется порядком, в котором код вызывает atexit (), это не относится к функциям atinit.Спецификация языка не требует заказа, вы ничего не могли бы сделать в своем коде, чтобы указать заказ.Результатом является SIOF.
Одна из возможных реализаций - указатели функций, испускающих компилятор в отдельном разделе.Компоновщик объединяет их, создавая список atinit.Если ваш компилятор сделает это, порядок инициализации будет определяться порядком, в котором вы связываете объектные файлы.Посмотрите на файл карты, вы должны увидеть раздел atinit, если ваш компилятор делает это.Он не будет называться atinit, но скорее всего будет какое-то имя с именем "init".Взглянув на исходный код CRT, который вызывает main (), вы также получите представление.