libffi 不能直接调用 C ++ 成员函数,因其仅支持 C ABI;需将成员函数包装为自由函数并显式传递 this 指针,且不可抛 C ++ 异常。

libffi 能不能直接调用 C++ 成员函数
不能。libffi 只支持 C ABI 的函数调用,也就是 plain function pointer + C-style calling convention。C++ 成员函数隐含 this 指针,且可能有 name mangling、virtual 表跳转、this-adjustment 等机制,libffi 无法自动处理。
常见错误现象:ffi_call 崩溃或传参错位,尤其是当目标函数看似“能调通”但读取参数时值全乱——大概率是把成员函数地址(如 &MyClass::foo)直接塞给了 libffi。
- 必须把成员函数包装成自由函数(
static或 lambda + capture via pointer),暴露为 C ABI - 如果需要访问对象状态,把
this当作第一个显式参数传入(即模拟“thunk”) - 避免在包装函数里抛 C++ 异常;libffi 不捕获它们,会直接穿透到 C 栈,导致未定义行为
如何用 libffi 调用带复杂参数的 C 函数(比如 float*、struct、const char*)
libffi 不解析类型语义,只认内存布局和 ABI 规则。你得自己告诉它每个参数的 ffi_type,并确保传入的指针 / 值符合对齐与生命周期要求。
使用场景:比如要动态调用 int process_data(const float* in, size_t len, Config* cfg)。
立即学习 “C++ 免费学习笔记(深入)”;
-
const float*和float*在 libffi 层没区别,都用&ffi_type_pointer -
struct必须预先用ffi_prep_cif配置其ffi_type,不能直接用&ffi_type_pointer代替——否则传进去的是地址,不是结构体内容本身 -
const char*同样用&ffi_type_pointer,但你要保证该字符串在ffi_call执行期间不被释放 - 注意大小端和结构体 padding:x86-64 上
struct {char a; int b;}占 8 字节,不是 5;libffi 依赖你传的ffi_type描述准确
为什么 ffi_prep_cif 返回 FFI_BAD_TYPEDEF
这是 libffi 最常卡住的地方,根本原因是传给它的 ffi_type * 数组里混入了非法或未初始化的类型描述符。
典型触发条件:
- 把
nullptr或栈上临时构造的ffi_type(比如局部变量)传进ffi_prep_cif—— libffi 内部会读取其elements字段,野指针直接崩 - 对数组类型误用
&ffi_type_pointer:比如函数参数是int arr[3],C ABI 中它退化为int*,所以仍用&ffi_type_pointer,而不是试图构造“array of 3 int”类型(libffi 不支持原生数组类型) - 在 Windows 上调用
__stdcall函数却用了FFI_DEFAULT_ABI:必须显式用FFI_STDCALL,否则 cif 初始化失败 - 参数数量超过 libffi 编译时限制(默认 64),但没检查
nargs是否越界
std::function 或 lambda 能不能直接交给 libffi
不能。libffi 只接受函数指针(void (*)() 类型),而 std::function 是类对象,lambda 若带捕获也是闭包对象,两者都不能隐式转成函数指针。
可行路径只有一条:用 reinterpret_cast 把自由函数地址喂给 libffi,其他一切封装逻辑由你手动桥接。
- 无捕获 lambda 可以用
+[](int x){return x*2;}转成函数指针,但仅限于编译期确定的表达式;动态生成逻辑不行 - 想传状态?把状态指针作为第一个参数传入,并在自由函数里
static_cast回原类型——这是唯一可控方式 - 别试图
memcpylambda 对象到可执行内存再调用:现代系统默认 W^X,且 libffi 不负责内存页权限管理
真正麻烦的从来不是怎么调,而是怎么安全地把 C++ 对象生命周期、异常边界、内存所有权跟纯 C 的 libffi 调用链对齐——这里漏一环,core dump 就在下一行。