Заполнить указатели глобальных функций в общей библиотеке (Solaris, Sun Studio)
-
26-10-2019 - |
Вопрос
Я создаю небольшую общую библиотеку C ++ вокруг библиотеки Fortran 95. Поскольку символы Fortran содержат .
В имени символа я должен использовать dlsym
Чтобы загрузить функцию Fortran в указатель функции C ++.
В настоящее время у меня есть куча глобальных указателей функций в файлах заголовков:
// test.h
extern void (*f)(int* arg);
и я заполняю их в соответствующем файле C ++:
// test.cc
void (*f))(int* = reinterpret_cast<void(*)(int*>(dlsym(RTLD_DEFAULT, "real_f.symbol_name_");
Вопросы:
- Если я сделаю это так, Когда эти указатели заполнены?
- Могу ли я предположить, что они будут загружены в мой исполняемый файл, который загружает эту библиотеку?
- Особенно, Могу ли я использовать эти функции в статически созданных объектах В моих исполняемых или других библиотеках? Или это страдает от Статическое фиаско порядка статического итализации?
- Если вышеупомянутый способ не верен, Какой самый элегантный способ заполнить эти указатели Такой, что их можно использовать в статических объектах в исполняемых файлах и других библиотеках?
Я использую компилятор Sun Studio на Solaris, если это имеет значение, но я также был бы заинтересован в решении GCC на Linux.
Решение
Где строка
f = reinterpret_cast<void(*)(int*)>(dlsym(RTLD_DEFAULT, "real_f.symbol_name_"));
происходит в test.cc
? Указатель будет инициализирован при выполнении строки (что, конечно, зависит от того, когда функция, которая содержит ее, называется). Или вы хотели написать
void (*f)(int* ) = reinterpret_cast<void(*)(int*>(dlsym(RTLD_DEFAULT, "real_f.symbol_name_");
? В этом случае указатель будет инициализирован во время статической инициализации. Это означает, что у вас все еще есть проблемы с инициализацией, если вы пытаетесь использовать указатели в конструкторе статического объекта.
Классическим решением для этого было бы использовать какой -то синглтон:
struct LibraryPointers
{
void (*f)(int* );
// ...
static LibraryPointers const& instance()
private:
LibraryPointers();
};
LibraryPointers const&
LibraryPointers::instance()
{
static LibraryPointers theOneAndOnly;
return theOneAndOnly;
}
LibraryPointers::LibraryPointers()
: f( reinterpret_cast<void(*)(int*)>(dlsym(RTLD_DEFAULT, "real_f.symbol_name_")) )
, // initialization of other pointers...
{
}
Затем оберните библиотеку в класс C ++, который использует эту структуру, чтобы получить адреса указателей.
И одно последнее замечание: reinterpret_cast
Вы пытаетесь сделать, не законно, по крайней мере, формально. (Я думаю, что и Sun CC, и G ++ примут это, однако.) Согласно POSIX, правильный способ получить указатель для функционирования от dlsym
было бы:
void (*f)(int* );
*reinterpret_cast<void**>(&f) = dlsym(...);
Однако это не поддается инициализации.