Поскольку вы уже знаете, что вам не следует полагаться на эту информацию, если это абсолютно необходимо, вот оно. Мое общее наблюдение за различными инструментальными цепочками (MSVC, gcc/ld, clang/llvm и т. Д.) Заключается в том, что порядок, в котором ваши объектные файлы передаются компоновщику, - это порядок, в котором они будут инициализированы.
Есть исключения из этого, и я не утверждаю, что все из них, но вот те, которые я побежал в себя:
1) GCC версии до 4.7 фактически инициализации в обратном порядке ссылки линия. This ticket in GCC - это когда произошло изменение, и оно нарушило множество программ, которые зависели от порядка инициализации (включая мой!).
2) В GCC и Clang использование constructor function priority может изменить порядок инициализации. Обратите внимание, что это относится только к функциям, объявленным как «конструкторы» (т. Е. Они должны выполняться так же, как и глобальный конструктор объектов). Я попытался использовать такие приоритеты и обнаружил, что даже с наивысшим приоритетом функции-конструктора все конструкторы без приоритета (например, обычные глобальные объекты, функции-конструкторы без приоритета) будут инициализированы . Другими словами, приоритет относится только к другим функциям с приоритетами, но настоящими гражданами первого класса являются те, кто не имеет приоритета. Чтобы это ухудшилось, это правило фактически является противоположным в GCC до 4.7 из-за вышеприведенной точки (1).
3) В Windows есть очень аккуратная и полезная функция входа в виде разделяемой библиотеки (DLL), называемая DllMain(), которая, если определена, будет запускаться с параметром «fdwReason», равным DLL_PROCESS_ATTACH, сразу после того, как все глобальные данные были initialized и до приложение-потребитель имеет возможность вызвать любые функции в DLL. Это очень полезно в некоторых случаях, и там абсолютно не является аналогичным поведением на других платформах с GCC или Clang с C или C++. Самое близкое, что вы найдете, это сделать функцию-конструктор с приоритетом (см. Выше пункт (2)), что абсолютно не то же самое и не будет работать для многих случаев использования, для которых работает DllMain().
4) Если вы используете CMake для генерации ваших систем сборки, что я часто делаю, я обнаружил, что порядок исходных исходных файлов будет порядком их результирующих объектных файлов, предоставленных компоновщику. Однако часто ваше приложение/DLL также связывается в других библиотеках, и в этом случае эти библиотеки будут на линии связи после ваших исходных файлов. Если вы хотите, чтобы один из ваших глобальных объектов был , сначала первый для инициализации, то вам повезло, и вы можете поместить исходный файл, содержащий этот объект, первым в списке исходных файлов.Однако, если вы хотите, чтобы один из них был очень последним для инициализации (который может эффективно реплицировать поведение DllMain()!), Вы можете сделать вызов add_library() с одним исходным файлом для создания статической библиотеки, и добавьте результирующую статическую библиотеку в качестве самой последней зависимости от ссылки в вашем запросе target_link_libraries() для вашего приложения/DLL. Будьте осторожны, что в этом случае ваш глобальный объект может быть оптимизирован, и вы можете использовать флаг --whole-archive, чтобы заставить компоновщик не удалять неиспользуемые символы для этого конкретного крошечного архивного файла.
Закрытие Совет
Чтобы быть абсолютно уверены в результате порядок инициализации вашего связанного приложения/разделяемой библиотеки, проходят --print-карту Л.Д. линкера и Grep для .init_array (или в GCC до 4,7, grep для .ctors). Каждый глобальный конструктор будет напечатан в том порядке, в котором он будет инициализирован, и помните, что порядок противоположный в GCC до 4,7 (см. Пункт (1) выше).
Мотивационный фактор для написания этого ответа заключается в том, что мне нужно было знать эту информацию, не имело другого выбора, кроме как полагаться на порядок инициализации, и обнаружил только разреженные части этой информации во всех других сообщениях SO и интернет-форумах. Большая часть его была получена благодаря большому количеству экспериментов, и я надеюсь, что это спасет некоторых людей от времени!
Мои предпочтения касаются всех глобальных переменных в одном модуле компиляции ... :-) – paercebal 2008-10-17 09:00:13
Предпочтительно вообще не нужны глобальные переменные. – 2008-10-17 09:02:32
Вы оба правы, но, к сожалению, это было неизвестно поколениям программистов, которые написали тонны библиотек и сторонний код, который мы использовали для использования ... – 2009-12-24 08:34:13