Why is the bytes order changed

See the example:

use std::{mem::{transmute_copy}};

fn main() {
    let s = String::from("hello world");
    let (a, b, c) = unsafe { transmute_copy::<_, (usize, usize, usize)>(&s) };
    let ((a1, a2, a3, a4, a5, a6, a7, a8), d, e) = unsafe {
        transmute_copy::<_, (
            (u8, u8, u8, u8, u8, u8, u8, u8),
            usize,
            usize
        )>(&s)
    };
    println!("0x{:x} 0x{:x} 0x{:x}", a, b, c);
    println!(
        "0x{:x} 0x{:x} 0x{:x} 0x{:x} 0x{:x} 0x{:x} 0x{:x} 0x{:x} 0x{:x} 0x{:x}",
        a1, a2, a3, a4, a5, a6, a7, a8, d, e
    );
}

The output:

0x55ed87f769d0 0xb 0xb
0xb 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x55ed87f769d0 0xb

0x55ed87f769d0 is the address/the memory location, I think.

Why in the first print, it's at the first 8 bytes, while in the second print, it's at the second 8 bytes?

I am not fully sure, but I think it is because the layout of tuples is not guaranteed to be anything (except for the unit tuple, which has 0 size and alignment 1).
For example, if we don't use a tuple (playground), then it works out fine.

2 Likes

Right, the memory order of tuple fields might not match the declaration order, since tuples are not #[repr(C)]. I believe Rust aggregates are currently ordered by decreasing alignment to allow natural packing, even in cases like this where that order doesn't make a difference. It might be the other way for enums to pack the tag first, I'm not sure. Either way, these details could change at any time.

You could make your own named tuple struct that does have #[repr(C)], but it's still not valid for you to "decode" String this way.

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.