Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting raw bytes from packed struct

I've got a struct which looks like this:

#[repr(packed)]
struct Header {
    some: u8,
    thing: u8,
}

How can I get raw bytes from it, that I could use for either a C library or socket interaction?

I was hoping to use transmute to solve the problem, but unfortunately this doesn't work:

let header = Header {....}
let header_bytes: &[u8] = unsafe { mem::transmute(header) };
let result = self.socket.write(header_bytes);

This fails with

error: transmute called on types with different sizes: &Header (64 bits) to &[u8] (128 bits)
like image 925
viraptor Avatar asked Feb 12 '23 00:02

viraptor


1 Answers

Edit: updated for Rust 1.x.

You can't transmute arbitrary thing to arbitrary thing (like Header to &[u8]) because transmute() is akin to reinterpret_cast in C++: it literally reinterprets the bytes which its argument consists of, and in order for this to be successful the source and the target type should have the same size. But even if Header and &[u8] had the same size, it wouldn't make sense to convert between them: Header is an actual value while &[u8] is a pointer with a size of data behind that pointer.

In order to interpret a piece of data as a slice of bytes you need to perform three steps: obtain a raw pointer to the data, convert it to a pointer to u8 and then convert that to a slice of u8. This means enhancing the raw pointer value with the length, which in this case is equal to the structure size. The last step can easily be done with std::slice::from_raw_parts():

use std::slice;
use std::mem;

let p: *const Header = &header;     // the same operator is used as with references
let p: *const u8 = p as *const u8;  // convert between pointer types
let s: &[u8] = unsafe { 
    slice::from_raw_parts(p, mem::size_of::<Header>())
};

However, doing this in most cases is not a good idea. Even though the struct is marked as packed, it still leaves the problem with the byte order, so at the very least the code which does this won't be portable (or rather, the data it serializes in such form may not be recoverable by the same program compiled for another architecture).

like image 91
Vladimir Matveev Avatar answered Feb 19 '23 15:02

Vladimir Matveev