C++如何向从DLL读取的未知签名函数传递任意数量JSON参数
C++ 动态调用DLL原生函数的参数传递解决方案
疑问解答:是否可以用单个vector代替多个参数传入原生函数?
完全不可行。C/C++原生函数的参数传递遵循固定的调用约定,要求参数按照指定顺序、内存布局压栈或者存入对应寄存器,vector是容器对象,内存布局和原生参数序列完全不匹配,且你无法修改目标函数实现的前提下,该思路完全不适用。
最优通用解决方案:使用libffi
libffi是专门用于运行时动态构造原生函数调用的底层工具库,不需要你预先知道目标函数的参数个数、类型,完全适配你从JSON读取参数、从DLL动态获取函数地址的场景,可彻底替换你现在手写固定参数个数if分支的临时方案。
核心实现步骤
- 从DLL中读取目标函数的地址,保存为void*类型的函数指针
- 遍历解析后的JSON参数,逐个匹配每个参数的类型,填充参数类型数组、参数值指针数组
- 初始化libffi的调用上下文
ffi_cif,指定调用约定、参数个数、返回值类型、参数类型数组 - 调用
ffi_call接口,传入上下文、函数指针、返回值存储地址、参数值指针数组,即可完成任意参数个数的函数调用
简化代码示例
#include <ffi.h> #include <vector> // 以下为示例逻辑,你可以根据自己的JSON解析逻辑适配 void* func = GetProcAddress(loaded_dll_handle, target_func_name.c_str()); int param_cnt = parsed_json_param_array.size(); std::vector<ffi_type*> arg_types(param_cnt); std::vector<void*> arg_values(param_cnt); // 遍历填充参数类型和值 for (int i = 0; i < param_cnt; ++i) { const auto& json_param = parsed_json_param_array[i]; if (json_param.is_integer()) { arg_types[i] = &ffi_type_sint32; static int val = json_param.as_integer(); arg_values[i] = &val; } else if (json_param.is_string()) { arg_types[i] = &ffi_type_pointer; static const char* val = json_param.as_string().c_str(); arg_values[i] = &val; } // 其他类型(浮点、指针、结构体等)可自行扩展匹配 } // 初始化调用上下文,此处默认使用cdecl调用约定,返回值为int类型 ffi_cif cif; ffi_status init_ret = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, param_cnt, &ffi_type_sint32, arg_types.data()); if (init_ret == FFI_OK) { int func_return_val; ffi_call(&cif, FFI_FN(func), &func_return_val, arg_values.data()); // func_return_val即为目标函数的返回结果 }
轻量替代方案(无第三方库依赖)
如果你的场景中允许限定最大参数个数,且不想引入libffi依赖,可以用C++11及以上版本的可变参数模板+编译期索引展开,自动生成不同参数个数的调用分支,不需要手动写if判断,代码可维护性远高于你现在的临时实现。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

