如何使用LuaJIT FFI创建指向现有数据的指针?

时间:2014-06-09 02:01:39

标签: pointers ffi luajit

我知道有一些使用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的指针,所以我可以正常指定它。

换句话说,有没有办法获取现有值的地址或创建指针?在创建它之前,我是否必须预见到我将使用该值做什么?

谢谢!

3 个答案:

答案 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");