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

4
我知道有一些使用LuaJIT FFI创建指针的示例,但大多数情况下这些示例并不指向现有数据。其中一个示例在这里: 如何将指针传递到LuaJIT ffi以用作输出参数? 我还没有成功地创建一个指向现有值的指针。据我所知,为了拥有指针类型,我必须知道我未来想要将指针指向它,例如:
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个回答

4
您无法获取cdata对象的地址的原因是所有cdata对象都会被垃圾回收。如果您继续思考这个问题,就会发现它意味着它们必须分配在Lua堆上,而不是一般的C堆上使用malloc。仅仅返回指向Lua堆中的指针非常不安全,因为垃圾回收器随时可能移动对象。
其中一个后果是你绝对不应该像rraallvv建议的那样做,因为你很可能会导致段错误。
当您调用ffi.new("GLuint[1]")时,您在Lua堆上分配了一个GLuint数组(LuaJIT将其称为“引用”类型)。这是可以接受的,因为当您调用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

3

在FFI中,无法获取指向cdata对象的指针。

我记得在LuaJIT邮件列表中读到过这是有意为之的,因为某些优化需要这样做,尽管我无法在存档中找到确切的消息。

到目前为止,我还没有需要获取cdata对象指针的需求;LuaJIT通过引用(类似于表格)引用cdata,并且type[1]技巧可用于输出参数。


这就是我担心的。我想我只能使用那种语法来初始化类型!我只是担心如果我对这个更改过于热衷,数组索引会成为一个新的性能问题。 - Lucien Greathouse

0

我可以通过一个复制cdata指针的C函数来实现这个

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接