4

LuaJit でいくつかの複雑なバイナリ メッセージを読み取る必要がある小さなアプリケーションを作成中です。

私は bit モジュールと string.rep をよく使っています。しかし、それはすべて非常に面倒です。私は LuaJit を使用するのが初めてで、FFI を使用するより簡単な方法があると思います。

CI では、次のような構造を宣言できます。

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)

次のエラーが生成されます。

だから私はキャストを試しました:

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

エラーはありませんが、ワイヤ上では間違っているようです。

4

2 に答える 2

13

ffi.string非文字列のようなパラメーターを使用する場合は、長さを明示的に指定する必要があります。

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

ptr が指すデータからインターンされた Lua 文字列を作成します。

オプションの引数 len が欠落している場合、ptr は「char *」に変換され、データは 0 で終了すると見なされます。文字列の長さは 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
于 2012-09-10T07:32:43.500 に答える
0

前回に誤りがありました。現在の luaffi 実装によれば、 にキャストできますvoid*。そのために使用ffi.string(ffi.cast("void*",ms),ffi.sizeof(ms))します。

于 2019-03-07T14:14:17.713 に答える