V.Molotov
V.Molotov

Reputation: 59

How are u128 numbers stored in memory?

I'm reconstructing u128 numbers passed over the internet. My idea is to break the number down into u8s on one end of the connection, send those and rebuild the u128 on the other end.

I attempted reconstructing a u8 buffer by casting its pointer to *const u8 to *const u128:

fn main() {
    let mut b = [0u8; 16];
    b[14] = 1;
    let addr = &b as *const u8 as *const u128;

    unsafe {
        println!("{:?}", &b as *const u8);
        println!("{:?}\n", b);

        println!("{:?}", addr);
        println!("n = {}", *addr);
    }
}

To my surprise, the generated output looked like this:

0x7efe2088
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]

0x7efe2088
n = 5192296858534827628530496329220096

I expected this array to contain

00000000 00000000 ... 00000001 00000000 = 256

Now I'm confused. Considering two different options as possibilities:

Which one of these is correct? Is there something I don't understand about the way Rust (or computers in general) store data?

Upvotes: 3

Views: 1129

Answers (1)

effect
effect

Reputation: 1455

Your confusion stems from endianness. This concept applies to computers in general, not just Rust. Some computer architectures are natively big-endian (e.g. MIPS), some are little endian (e.g. x86), and some can be both (e.g. ARM)!.

For transporting the numbers over the internet, you should choose what order you want send them (either big-endian or little endian; big-endian is the traditional choice, though little-endian systems are more common these days), and then explicitly convert when sending and receiving. This way, your program will still work even if the two computers talking have a different endianness (for example, MIPS and x86-64 are different).

As @loganfsmyth notes, Rust has built-in methods to do this conversion from a u128 to an array of u8s (and vice-versa), these methods are:

Upvotes: 8

Related Questions