能否为C++函数自定义无名称修饰的符号名以直接从C语言调用?
需求可行性说明
这个需求可以实现,但没有标准C++原生语法支持,需要依赖对应编译器的扩展能力,不需要额外写中转函数的封装逻辑。
主流编译器实现方案
GCC/Clang 平台
使用编译器的alias属性,给C++成员函数的修饰后符号绑定一个无名称修饰的自定义别名:
class Foo { public: Foo(); void some_method(int); int a_; }; // 给Foo::some_method绑定无修饰的别名Foo_some_method // 后面的_ZN3Foo11some_methodEi是GCC/Clang下Foo::some_method(int)的默认修饰后符号 // 可通过nm命令编译目标文件后查询对应符号 extern "C" void Foo_some_method(Foo*, int) __attribute__((alias("_ZN3Foo11some_methodEi")));
C侧调用时需要注意,C++非静态成员函数默认携带隐藏的this指针作为第一个参数,所以C侧声明和调用写法如下:
// C侧头文件 struct Foo; // 前置声明即可,不需要暴露类布局 void Foo_some_method(struct Foo* foo, int param);
调用时直接传入C++侧创建的Foo实例指针和对应参数即可,没有任何中转开销。
MSVC 平台
通过链接器导出选项给符号绑定别名:
class Foo { public: Foo(); void some_method(int); int a_; }; // ?some_method@Foo@@QAEXH@Z为MSVC下Foo::some_method(int)的默认修饰后符号 // 可通过dumpbin命令编译目标文件后查询对应符号 #pragma comment(linker, "/EXPORT:Foo_some_method=?some_method@Foo@@QAEXH@Z")
C侧的调用声明和GCC/Clang场景完全一致。
注意事项
- 该方案高度依赖编译器和平台,不同编译器的名称修饰规则完全不同,一旦C++侧的函数签名、调用约定、类命名空间等信息发生变更,需要同步更新对应的修饰后符号字符串,否则会出现符号找不到的错误。
- 该方案仅对非虚成员函数稳定可用,虚成员函数需要额外处理虚表布局,C侧调用复杂度很高,不推荐使用该方案。
- 如果需要跨编译器兼容,仍然建议使用
extern "C"封装函数的方案,虽然有极薄的中转层,但可移植性高,维护成本远低于编译器扩展方案。
内容的提问来源于stack exchange,提问作者moamen
相关产品推荐
相关产品推荐

