如何通过LuaJIT FFI获取C函数输出的char*缓冲区值?
LuaJIT FFI调用C函数获取char*缓冲区值的问题解决
问题背景
你有一个编译好的SO文件,其中get_value函数会向传入的char*缓冲区写入数据,现在需要通过LuaJIT FFI调用该函数并获取缓冲区中的字符串值。你的C代码如下:
typedef struct MyStruct_s { int a; }MyStruct; void *init(char* host, int timeout) { void *handle = (void*)malloc(sizeof(MyStruct)); if(handle == NULL) { printf("create myStruct falied\n"); } return handle; } int get_value(void *handle, char *buffer, int *len) // 我希望将buffer传入Lua { MyStruct* my_handle = (MyStruct*)handle; // my_handle执行操作 if(buffer == NULL) { printf("buffer is NULL\n"); return -1; } char tmp[10] = "hi there"; memcpy(buffer, tmp, strlen(tmp)); *len = strlen(tmp); return 0; }
你尝试的Lua代码存在几个问题,导致无法正常工作,下面是修正方案:
错误分析与修正步骤
修正
init函数的FFI声明
你的C代码中init函数需要host和timeout两个参数,但Lua的ffi.cdef里写成了无参版本,这会导致调用init时参数不匹配,返回的handle可能无效。需要同步声明参数:ffi.cdef [[ void *init(char* host, int timeout); int get_value(void *zkhandle, char *buffer, int *len); ]]调用时也要传入对应参数,比如:
local handle = zkclient.init("127.0.0.1", 3000)正确创建长度指针
你直接用ffi.cast("int *", len)把整数1024转换成指针,这是错误的——这里需要的是一个指向int变量的指针,而不是把数值当成地址。应该先创建一个int类型的变量,再取它的地址:local node_len = ffi.new("int[1]", 1024) -- 创建一个长度为1的int数组,初始值1024,数组名就是指针将char数组转换为Lua字符串
调用get_value后,node_value是FFI的char数组,需要用ffi.string把它转换成Lua原生字符串,注意要传入实际的长度(node_len[0]),避免读取到多余的空字符:local lua_str = ffi.string(node_value, node_len[0])
完整修正后的Lua代码
local ffi = require("ffi") local zkclient = ffi.load("zkclient") ffi.cdef [[ void *init(char* host, int timeout); int get_value(void *zkhandle, char *buffer, int *len); ]] -- 注意传入init函数需要的host和timeout参数 local handle = zkclient.init("127.0.0.1", 3000) if handle == nil then kong.log.info("handle is nil ") return nil end -- 初始化1024大小的char缓冲区 local node_value = ffi.new('char[1024]', {0}) -- 创建存储长度的int指针,初始值为缓冲区大小 local node_len = ffi.new("int[1]", 1024) local result = zkclient.get_value(handle, node_value, node_len) if result == 0 then -- 将FFI char数组转换为Lua字符串 local lua_str = ffi.string(node_value, node_len[0]) kong.log.info("获取到的值:", lua_str) else kong.log.info("调用get_value失败") end
额外说明
ffi.new('char[1024]', {0})的写法是正确的,它会初始化一个1024字节的char数组并将所有元素置0。- 确保SO文件的路径正确,
ffi.load会在系统默认库路径查找,如果SO在自定义路径,需要用绝对路径或者设置环境变量。
内容的提问来源于stack exchange,提问作者Klen
相关产品推荐
相关产品推荐

