【问题标题】:How do I convert a cdata structure into a lua string?如何将 cdata 结构转换为 lua 字符串?
【发布时间】:2012-09-02 20:54:52
【问题描述】:

我正在编写一个小应用程序,需要在 LuaJit 中读取一些复杂的二进制消息。

我一直在使用 bit 模块和 string.rep 很多。然而,这一切都非常麻烦。我是使用 LuaJit 的新手,我认为使用 FFI 可能会更简单。

在 C 中我可以声明这样的结构:

struct mystruct
{
  uint32_t field1;
  char     field2[6];
  uin64_t  field3;
  short    field4;
} __attribute__(packed);

在阅读 LuaJit 的 FFI 时,您似乎可以声明

ffi.cdef[[
    #pragma pack(1)
    struct mystruct
    {
      uint32_t field1;
      char     field2[6];
      uin64_t  field3;
      short    field4;
    };
]]

然后我可以创建一个 mystruct 并访问如下字段:

local ms = ffi.new("mystruct")
ms.field1 = 32;
// ... etc

但是,如何将其转换回 lua 字符串?

我试过这个,但它似乎没有达到我想要的效果。

local s = tostring(ms)

还有这个:

local s = ffi.string(ms)

产生以下错误“bad argument #1 to 'string' (cannot convert 'struct mystruct' to 'const char *')”

所以我尝试了一个演员表:

local s = ffi.string(ffi.cast("char*", ms))

没有错误,但在电线上看起来有问题。

【问题讨论】:

  • 哎呀,应该是打包而不是打包。固定。
  • 你说的“它看起来不对”是什么意思?你看到了什么?您期望/希望看到什么?

标签: lua ffi luajit


【解决方案1】:

在使用ffi.string 和非字符串参数时,您必须明确指定长度:

str = ffi.string(ptr [,len])

从 ptr 指向的数据创建一个实习 Lua 字符串。

如果缺少可选参数 len,ptr 将转换为“char *”,并且假定数据以零结尾。字符串的长度是用 strlen() 计算的。

运行以下代码时,我得到了预期的(小端)结果:

ffi = require 'ffi'
ffi.cdef[[
    typedef unsigned long uint32_t;
    typedef unsigned long long uint64_t;
    #pragma pack(1)
    struct mystruct
    {
      uint32_t field1;
      char     field2[6];
      uint64_t  field3;
      short    field4;
    };
]]

function string.tohex(str)
    return (str:gsub('.', function (c)
        return string.format('%02X', string.byte(c))
    end))
end

ms = ffi.new('struct mystruct', 1, {2, 3, 4, 5, 6, 7}, 8, 9)
s = ffi.string(ms, ffi.sizeof(ms)) -- specify how long the byte sequence is
print(s:tohex()) --> 0100000002030405060708000000000000000900

更新:我知道这不是原始问题的一部分,但我刚刚学会了这个技巧,为了完整起见,这里有一种将 Lua 字符串转换回 FFI cdata 的方法:

    data = ffi.new('struct mystruct')   -- create a new cdata
    ffi.copy(data, s, ffi.sizeof(data)) -- fill it with data from Lua string 's'
    print(data.field1, data.field4)     --> 1   9

【讨论】:

  • 它不必被复制。一个简单的cast 就可以了。 ``` local st = ffi.cast('struct mystruct*', s) print(st.field4) ```
【解决方案2】:

前面有错误。 根据当前的 luaffi 实现,您可以将其转换为 void* 。使用ffi.string(ffi.cast("void*",ms),ffi.sizeof(ms)) 这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-02
    • 1970-01-01
    • 2021-06-28
    • 1970-01-01
    • 2013-12-30
    • 1970-01-01
    • 1970-01-01
    • 2014-09-14
    相关资源
    最近更新 更多