0

我正在围绕 Fortran 95 库创建一个小型 C++ 包装共享库。由于 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_");

问题:

  1. 如果我这样做,这些指针何时填充?
  2. 我可以假设它们被加载到我加载这个库的可执行文件中吗?
  3. 特别是,我可以在我的可执行文件或其他库中静态创建的对象中使用这些函数吗?或者这是否受到静态初始化命令失败的影响?
  4. 如果上述方法不正确,那么填充这些指针以便它们可以在可执行文件和其他库中的静态对象中使用的最优雅的方法是什么?

我在 Solaris 上使用 Sun Studio 编译器,如果这会有所不同,但我也对 Linux 上的 GCC 解决方案感兴趣。

4

1 回答 1

1

线在哪里

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(...);

然而,这并不适合初始化。

于 2011-10-19T08:29:24.827 回答