Search code examples
castingluaffiunpackluajit

How to cast string to uint32 luajit ffi


Consider that str is a binary string which contains an unsigned int 32 at position 13.

I tried this:

local value = ffi.cast("uint32_t", ffi.new("char[4]", str:sub(13,16)))

However, the data returned is a "cdata" of type unsigned int and I don't now how to get the actual value (the Int)


Solution

  • In general I agree with Egor Skriptunoffs answer. For a more generalized aproach (and maybe soemwhat overkill for this particular case) one could use a union type

    local ffi = require 'ffi'
    
    local union_type = ffi.typeof [[
      union {
        char bytes[4];
        uint32_t integer;
      }
    ]]
    
    local union = union_type { bytes = 'abcd' }
    
    print(string.format('0x%x', union.integer))
    

    note that you need to worry about endianness here; you can confirm your systems endianness with ffi.abi('le') or ffi.abi('be'). If you're getting your string from somewhere else (like over the network), its endianness is most likely documented somewhere.

    Suppose you want to interpret the string fromt he above example (abcd) as big endian; then you could do this

    local union do
      if ffi.abi('le') then
        union = union_type { bytes = ('abcd'):reverse() }
      else
        union = union_type { bytes = 'abcd' }
      end
    end
    

    If the system is little endian, reverse the string. Otherwise leave it as is.