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,所以我可以正常指定它。

换句话说,有没有办法获取现有值的地址或创建指向现有值的指针?在创造价值之前,我是否必须预见我将如何处理价值?

谢谢!

4

3 回答 3

4

无法获取 cdata 对象地址的原因是所有 cdata 对象都被垃圾回收。如果你停下来思考一下它的逻辑结论,你会发现这意味着它们必须分配在 Lua 堆上,而不是一般的 C 堆上malloc。只将指针返回到 Lua 堆中是非常不安全的,因为垃圾收集器可能随时出现并移动对象。

这样做的一个后果是你绝对不应该做 rraallvv 建议的事情,因为你可能会导致段错误。

当您调用时,ffi.new("GLuint[1]")您在 Lua 堆上分配一个 s 数组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
于 2015-05-27T02:46:00.350 回答
3

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

我记得在 LuaJIT 邮件列表中读到,这是有意为一些优化工作而进行的,尽管我在存档中找不到确切的消息。

到目前为止,我还不需要获取 cdata 对象的指针。LuaJIT 通过引用(类似于表)引用 cdata,并且该type[1]技巧适用于 out 参数。

于 2014-06-09T04:12:26.110 回答
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");
于 2015-05-12T08:47:11.207 回答