Does Rust have a way to convert several bytes to a number?
Solution 1
There is T::from_str_radix
to convert from a string (you can choose the base and T
can be any integer type).
To convert an integer to a String
you can use format!
:
format!("{:x}", 42) == "2a"
format!("{:X}", 42) == "2A"
To reinterpret an integer as bytes, just use the byte_order
crate.
Old answer, I don't advise this any more:
If you want to convert between u32
and [u8; 4]
(for example) you can use transmute
, it’s what it is for.
Note also that Rust has to_be
and to_le
functions to deal with endianess:
unsafe { std::mem::transmute::<u32, [u8; 4]>(42u32.to_le()) } == [42, 0, 0, 0]
unsafe { std::mem::transmute::<u32, [u8; 4]>(42u32.to_be()) } == [0, 0, 0, 42]
unsafe { std::mem::transmute::<[u8; 4], u32>([0, 0, 0, 42]) }.to_le() == 0x2a000000
unsafe { std::mem::transmute::<[u8; 4], u32>([0, 0, 0, 42]) }.to_be() == 0x0000002a
Solution 2
A u32
being 4 bytes, you may be able to use std::mem::transmute
to interpret a [u8; 4]
as a u32
however:
- beware of alignment
- beware of endianness
A no-dependency solution is simply to perform the maths, following in Rob Pike's steps:
fn as_u32_be(array: &[u8; 4]) -> u32 {
((array[0] as u32) << 24) +
((array[1] as u32) << 16) +
((array[2] as u32) << 8) +
((array[3] as u32) << 0)
}
fn as_u32_le(array: &[u8; 4]) -> u32 {
((array[0] as u32) << 0) +
((array[1] as u32) << 8) +
((array[2] as u32) << 16) +
((array[3] as u32) << 24)
}
It compiles down to reasonably efficient code.
If dependencies are an option though, using the byteorder crate is just simpler.
Walking.In.The.Air
I like create stable bulletproof systems. I's my fault: they are too complex and this lake a lot of time. However I can do nothing about it.
Updated on July 01, 2020Comments
-
Walking.In.The.Air almost 4 years
And convert a number to a byte array?
I'd like to avoid using
transmute
, but it's most important to reach maximum performance. -
Walking.In.The.Air about 8 yearsAs I understand T::from_str_radix convert from string, not from hex. And "format!" seems to be slowpoke, however I do really need performance.
-
mcarton about 8 yearsWhat do you call hex then? The base only matters when the number is represented as a string. Otherwise
42
and0x2a
are the same integer. -
Walking.In.The.Air about 8 yearsFor example I have several bytes (bytes: &[u8; 4]) and need to get int (u32) from it.
-
mcarton about 8 yearsIn that case the base does not matter at all, it’s just bytes.
-
Walking.In.The.Air about 8 yearsYes I mean exactly it. Base doesn't matter. But how to get value of this 4 bytes into u32 variable?
-
mcarton about 8 yearsI’ve added an example with transmute taking care of endianess issues.
-
gavin about 8 yearsI would recommend the byte order crate over raw transmutes; it is a safe interface, and makes sure you're considering endianness.
-
mcarton about 8 yearsLooks even better, I did not know it
-
starblue about 8 yearsDon't use transmute, it is dangerous and will cause portability headaches when endianness changes. If you don't want to use the byte_order crate use bit operations (shift by multiples of 8 bits and or), the compiler will compile it into efficient code.
-
starblue about 8 yearsAs a matter of style I would use
|
instead of+
(and Rob Pike seems to agree).