【问题标题】:How can I create a pointer to existing data using the LuaJIT FFI?如何使用 LuaJIT FFI 创建指向现有数据的指针?
【发布时间】:2015-05-28 03:37:03
【问题描述】:

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

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

谢谢!

【问题讨论】:

    标签: pointers ffi luajit


    【解决方案1】:

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

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

    当你调用 ffi.new("GLuint[1]") 时,你会在 Lua 堆上分配一个 GLuints 数组(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
    

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 这就是我害怕的。我想我将使用该语法初始化类型!如果我对这种变化过于热心,我只是担心数组索引会成为一个新的性能问题。
      【解决方案3】:

      我可以用一个像这样复制 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");
      

      【讨论】:

        猜你喜欢
        • 2014-09-03
        • 1970-01-01
        • 2023-03-12
        • 2015-03-03
        • 1970-01-01
        • 2018-09-20
        • 2021-04-05
        • 1970-01-01
        • 2019-11-30
        相关资源
        最近更新 更多