能否在LuaJIT中取消ffi.cdef定义的符号?
解决LuaJIT FFI全局类型冲突的问题
问题本质
LuaJIT的ffi.cdef是全局的类型注册表——所有通过它定义的符号会被全局共享。你先后定义了两个同名但参数不同的func,后定义的并不会覆盖前者,反而会造成类型冲突。调用第二个库的func时,LuaJIT依然用第一个注册的void func(int)签名做参数校验,自然就报参数数量错误了。
你之前把库对象置空再GC没用,因为全局类型注册表的定义和库对象是分开的,不会随库对象被回收。
可行的解决办法
方法1:用函数指针类型显式转换
给不同签名的函数定义独立的函数指针类型,加载库后把符号地址转成对应类型再调用:
-- 先定义两种不同的函数指针类型 ffi.cdef [[ typedef void (*Func1)(int); typedef void (*Func2)(int, int); ]] -- 调用liba的func local liba = ffi.load("a") local func_a = ffi.cast("Func1", liba.func) func_a(1) -- 调用libb的func local libb = ffi.load("b") local func_b = ffi.cast("Func2", libb.func) func_b(1, 2)
方法2:临时转换类型(适合单次调用)
如果不需要复用类型,也可以直接在调用时临时指定类型转换:
-- 调用liba local liba = ffi.load("a") ffi.cast("void(*)(int)", liba.func)(1) -- 调用libb local libb = ffi.load("b") ffi.cast("void(*)(int, int)", libb.func)(1, 2)
方法3:用元类型包装库(更规范)
如果需要多次调用同一个库的函数,可以用元类型把库和对应类型绑定起来:
-- 定义liba对应的结构类型 local LibAType = ffi.metatype("struct { void (*func)(int); }", {}) local liba = ffi.cast("LibAType*", ffi.load("a")) liba.func(1) -- 定义libb对应的结构类型 local LibBType = ffi.metatype("struct { void (*func)(int, int); }", {}) local libb = ffi.cast("LibBType*", ffi.load("b")) libb.func(1, 2)
重要提醒
LuaJIT的全局类型注册表一旦注册了类型,就没法修改或删除,直到VM退出。所以千万别重复定义同名但签名不同的符号,否则必然会出现冲突。显式类型转换是绕过这个问题最直接的方式。
内容的提问来源于stack exchange,提问作者bod
相关产品推荐
相关产品推荐

