我有一个系统,我给用户一个函数原型,用户必须实现它。现在,我使用 g++ 编译该文件并使用 dlopen 和 dlsym 动态加载它以进一步处理它。现在,我在这里读到:
要加载 c++ 函数,我们必须在函数之前使用 extern "C"。现在,问题是,我不想向用户展示事情是如何工作的。我不想在函数之前显示用户 extern "C"。
有什么办法可以避免吗?
我有一个系统,我给用户一个函数原型,用户必须实现它。现在,我使用 g++ 编译该文件并使用 dlopen 和 dlsym 动态加载它以进一步处理它。现在,我在这里读到:
要加载 c++ 函数,我们必须在函数之前使用 extern "C"。现在,问题是,我不想向用户展示事情是如何工作的。我不想在函数之前显示用户 extern "C"。
有什么办法可以避免吗?
您可以直接使用损坏的 C++名称。
例如,如果您有一个 C++ 函数void my_plugin(int foo)
,C++ 编译器将破坏该名称。一旦知道了损坏的函数名称,就可以在该名称上使用 dlopen()。
例如
# nm libmyplugin.so |grep my_plugin
00000000 T _Z9my_plugini
所以这里我们的函数被命名为 _Z9my_plugini ,你可以这样做
func = dlsym(handle, "_Z9my_plugini");
传统上,不同的编译器可能会以不同的方式修改名称,因此这可能非常脆弱,尽管如今大多数 C++ 编译器都会同意在给定平台上使用标准方式修改名称。
但是,您的用户将是程序员,他们通常会理解将条目公开给动态加载的库作为extern "C"
既然您使用的是 C++,为什么不只导出一个(或两个)函数,这些函数将简单地返回一个指向某种纯虚类的指针,比如说IMyModule
?一个(或两个)导出的extern "C"
函数将类似于extern "C" IMyModule * create_instance_IMyModule();
(and extern "C" void delete_instance_IMyModule(IMyModule const *);
)。
在每个声明之前的另一种替代方法extern "C"
是使用块样式语法:
extern "C" {
void my_callback();
int other_functionality( foo * );
}
通常extern "C" {
,右大括号}
被包裹在宏中,这些宏以__cplusplus
内置宏为条件,因此也可以从纯 C 中使用标头。这也封装了您认为令人反感的部分。
无论如何,我看不出有什么大不了的。如果用户可以用 C++ 编写,他们应该有能力extern "C"
在库文档告诉他们时封装他们的 C 接口函数原型。