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