Change endianness in reinterpret

Hello!

I am trying to reinterpret a Vector of bytes into a predefined type I have. However, primitive types are always intepreted as being little endian. Is there any way I can change this?

MWE:

julia> struct P
           a::UInt32
           b::UInt8
           c::UInt8
           d::UInt16
           end

julia> struct Q
           a::UInt32
           b::UInt32
           end

julia> a = [0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08]

julia> reinterpret(P,a)
1-element reinterpret(P, ::Vector{UInt8}):
 P(0x04030201, 0x05, 0x06, 0x0807)

julia> reinterpret(Q,a)
1-element reinterpret(Q, ::Vector{UInt8}):
 Q(0x04030201, 0x08070605)

Can I get inner integers to be 0x01020304 and so on?

Thanks!

There might be a more elegant way, but this works:

Q((hton(getfield(only(reinterpret(Q, a)), f)) for f in fieldnames(Q))...)
1 Like

Yep, I had already thought of that. However, the solution gets more complicated when, instead of a and b being easy UInt types, they become more complex. For example, something along the lines of:

julia> struct Q
           a::UInt32
           b::UInt32
           end
julia> struct P
           a::Q
           b::UInt8
           c::UInt8
           d::UInt16
           end

In this case, the algorithm must be recursive and, although possible, it becomes a pain in the ass

You could automate writing a recursive ntoh method for your struct with a macro or similar, but unless you have a lot of such structs (or a lot of struct fields), it’s probably easier to just write ntoh methods by hand:

Base.ntoh(x::Q) = Q(ntoh(x.a), ntoh(x.b))
Base.ntoh(x::P) = P(ntoh(x.a), ntoh(x.b), ntoh(x.c), ntoh(x.d))

Then just do ntoh.(reinterpret(P, bytes)).

To define both ntoh and hton, you can use a simpler metaprogramming trick:

for f in (:ntoh, :hton)
    @eval Base.$f(x::Q) = Q($f(x.a), $f(x.b))
    @eval Base.$f(x::P) = P($f(x.a), $f(x.b), $f(x.c), $f(x.d))
end
6 Likes