我知道有一些使用LuaJIT FFI创建指针的例子,但其中大部分并未指向现有数据。其中一个例子就是: How to pass a pointer to LuaJIT ffi to be used as out argument?
我无法成功做的一件事是创建一个指向现有值的指针。据我所知,为了得到一个指针类型,我必须知道我希望在将来的某个时刻指向它,如:
local vao = ffi.new("GLuint[1]")
gl.GenVertexArrays(1, vao)
gl.BindVertexArray(vao[0])
在这里,我知道glGenVertexArrays需要一个指向vao
的指针,因此我将其指定为GLuint [1]。在C中,我会做类似以下的事情:
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
在这里,我不知道我需要一个指向vao
的指针,所以我可以正常指定它。
换句话说,有没有办法获取现有值的地址或创建指针?在创建它之前,我是否必须预见到我将使用该值做什么?
谢谢!
答案 0 :(得分:3)
无法在FFI中获取指向cdata对象的指针。
我记得在LuaJIT邮件列表中读到这是为了使一些优化工作有意为之,但我无法在档案中找到确切的信息。
到目前为止,我还没有得到cdata对象的指针; LuaJIT通过引用引用cdata(类似于表),type[1]
技巧适用于out参数。
答案 1 :(得分:3)
您无法获取cdata对象的地址的原因是所有cdata对象都是垃圾回收的。如果你停下来并认为通过它的逻辑结论,你会发现这意味着它们必须在Lua堆上分配,而不是malloc
将使用的一般C堆。将指针返回到Lua堆是非常不安全的,因为垃圾收集器可以随时移动并移动对象。
这样做的一个后果是你绝对不应该做rraallvv所建议的,因为你可能会导致段错误。
当你调用ffi.new("GLuint[1]")
时,你在Lua堆上分配了一个GLuint
数组(LuaJIT称之为'引用'类型)这是 ok 因为你打电话的时候进入GenVertexArrays()
(1)GC无法运行,因为你忙于执行C代码,(2)GenVertexArrays()
没有保留指针,所以你不必担心陈旧指针稍后被访问。
然而,LuaJIT的FFI提供了足够的功能,我们可以构建自己的分配装置。以下代码应该(尚未完全测试此版本)在C堆上分配数据并安装默认终结器以释放它。如果你查看所有使用的FFI函数,你应该对事物有更好的认识。
local function SafeHeapAlloc(typestr, finalizer)
-- use free as the default finalizer
if not finalizer then finalizer = ffi.C.free end
-- automatically construct the pointer type from the base type
local ptr_typestr = ffi.typeof("$ *", typestr)
-- how many bytes to allocate?
local typesize = ffi.sizeof(typestr)
-- do the allocation and cast the pointer result
local ptr = ffi.cast(ptr_typestr, ffi.C.malloc(typesize))
-- install the finalizer
ffi.gc( ptr, finalizer )
return ptr
end
答案 2 :(得分:0)
我能够使用C函数来复制cdata指针,就像这样
void cdataToPointer(void *cdata, void **pointer) {
*pointer = cdata;
}
// ...
void *mycdata = NULL;
lua_pushlightuserdata(L, &mycdata);
lua_setglobal(L, "__TEMP_USERDATA__");
luaL_dostring(L,
"local ffi = require'ffi'\n"
"ffi.cdef[[\n"
" void cdataToPointer(void *cdata, void **pointer);\n"
"]]\n"
"ffi.C.cdataToPointer(mycdata, __TEMP_USERDATA__)\n");