Вот когда точно статики инициализируются после main
Все-таки есть стопроцентный способ создать условия, чтобы этот эффект проявился.
Как вы знаете, есть 2 вида библиотек: статические и динамические. Код статических библиотек вставляется в основной код программы в то время, как код динамических библиотек подгружается в рантайме.
Так вот есть способы в любой момент исполнения программы руками подгрузить shared library и использовать ее символы, даже ничего не зная о ней на этапе линковки объектников!
На юниксах это системный вызов dlopen. Он принимает путь к библиотеки и возвращает ее хэндл. Через этот хэндл можно получать указатели на сущности из либы.
Естественно, что раз бинарник ничего не знал о сущностях библиотеки до ее explicit подгрузки, а библиотека просто лежала камнем в файловой системе, то буквально никакой код библиотеки не может быть выполнен до ее подгрузки. А значит, если мы открываем либу в main(), то только в этот момент начинается вся динамическая инициализация сущностей либы. Поэтому значение ее переменных со static storage duration устанавливается после входа в main()!
Минимальный пример:
Вывод:
Чтобы запустить это дело(на примере gcc), нужно:
1️⃣ Скомпилировать объектный файл из source.cpp g++ -c -fpic -std=c++17 source.cpp
2️⃣ Превратить его в библиотеку g++ -shared -o libsource.so source.o
3️⃣ Скомпилировать main.cpp g++ -o test main.cpp -std=c++17
4️⃣ Запустить ./test
Важно отметить, что о существовании библиотеки исполняемый файл test вообще не в курсе. Также не нужно добавлять путь до либы в какой-нибудь $LD_LIBRARY_PATH.
Если библиотеку сликовать с бинарем сразу же и подгружать ее неявно, то порядок инициализации будет снова неопределен в соотвествии с предыдущим постом. И скорее всего такого эффекта в этом случае не будет.
Вот такие интересности существуют в мире инициализации статиков. Пост не несет какого-то особого смысла, разве что познакомить некоторых читателей с таким вот явным способом загрузки динамических либ в код.
Dig deeper. Stay cool.
#compiler
Все-таки есть стопроцентный способ создать условия, чтобы этот эффект проявился.
Как вы знаете, есть 2 вида библиотек: статические и динамические. Код статических библиотек вставляется в основной код программы в то время, как код динамических библиотек подгружается в рантайме.
Так вот есть способы в любой момент исполнения программы руками подгрузить shared library и использовать ее символы, даже ничего не зная о ней на этапе линковки объектников!
На юниксах это системный вызов dlopen. Он принимает путь к библиотеки и возвращает ее хэндл. Через этот хэндл можно получать указатели на сущности из либы.
Естественно, что раз бинарник ничего не знал о сущностях библиотеки до ее explicit подгрузки, а библиотека просто лежала камнем в файловой системе, то буквально никакой код библиотеки не может быть выполнен до ее подгрузки. А значит, если мы открываем либу в main(), то только в этот момент начинается вся динамическая инициализация сущностей либы. Поэтому значение ее переменных со static storage duration устанавливается после входа в main()!
Минимальный пример:
// lib.cpp
struct CreationMomentShower {
CreationMomentShower(int num=0) : data{num} {
std::cout << "Created object with data " << num << std::endl;
}
int data;
};
struct Use {
static inline CreationMomentShower help{6};
};
// main.cpp
#include <iostream>
#include <dlfcn.h>
int main()
{
std::cout << "Main has already started" << std::endl;
void* libraryHandle = dlopen("libsource.so", RTLD_NOW);
if (libraryHandle == nullptr) {
std::cerr << dlerror() << std::endl;
return 1;
}
dlclose(libraryHandle);
}
Вывод:
Main has already started
Created object with data 6
Чтобы запустить это дело(на примере gcc), нужно:
1️⃣ Скомпилировать объектный файл из source.cpp g++ -c -fpic -std=c++17 source.cpp
2️⃣ Превратить его в библиотеку g++ -shared -o libsource.so source.o
3️⃣ Скомпилировать main.cpp g++ -o test main.cpp -std=c++17
4️⃣ Запустить ./test
Важно отметить, что о существовании библиотеки исполняемый файл test вообще не в курсе. Также не нужно добавлять путь до либы в какой-нибудь $LD_LIBRARY_PATH.
Если библиотеку сликовать с бинарем сразу же и подгружать ее неявно, то порядок инициализации будет снова неопределен в соотвествии с предыдущим постом. И скорее всего такого эффекта в этом случае не будет.
Вот такие интересности существуют в мире инициализации статиков. Пост не несет какого-то особого смысла, разве что познакомить некоторых читателей с таким вот явным способом загрузки динамических либ в код.
Dig deeper. Stay cool.
#compiler