Re-interpret slice of bytes (e.g. [u8]) as slice of [f32]

  1. is transmute necessary for this or can it be done safely with pointer casting?

  2. where does endianness come into the picture?

In my particular use case, I know that the data is stored little-endian and I'm targeting wasm which is also little-endian... though I'm not sure if I want to gloss over these facts in the code

(fwiw this thread seems highly related as does the section on type conversion in the nomicon)

slice::align_to is probably what you are searching for:

unsafe {
    let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
    let (prefix, ints, suffix) = bytes.align_to::<u32>();
    // less_efficient_algorithm_for_bytes(prefix);
    // more_efficient_algorithm_for_aligned_shorts(shorts);
    // less_efficient_algorithm_for_bytes(suffix);
}
1 Like

do you mind explaining a bit why this is better than just a transmute?

If the byte array is not aligned correctly, the conversion is undefined behavior irregardless of you transmute or cast the reference to the slice.

slice::align_to would not help in this case either, because you'd have bytes belonging to different floats be combined into one float.

2 Likes

thanks! I think I'll need to read up on data alignment to understand better

my naive thought right now is that there is no alignment issue, because the first byte of the [u8] is the first byte of the [f32]...?

A pointer to an f32 must be divisible by 4, but this is not required for an u8, so the conversion may violate this.

pointer as in the numerical value of the address itself?

Yes

1 Like

If you control the creation of the array, you could allocate it as an array of f32 and transmute that to an array of bytes, which is always OK.

That said, you should use a pointer cast instead of transmute. And don't try transmuting the underlying Vec. Only the slices

interesting... so the use-case I have is arbitrary data is loaded and then parts of it are re-interpreted as [f32] (and other parts remain [u8])

If the address is divisible by four, you can cast the pointer, but otherwise you'll have to copy it into a properly aligned container.

copy or just re-slice? seems align_to doesn't copy?

Oh nm I see you addressed that above...

Using align_to on e.g. [0,0,1,1,1,1,0,0] may result in e.g. [0,0], [1,1,1,1], [0,0] which doesn't sound like what you want

1 Like

Seems like this is a fairly common need, I'm surprised there's nothing built-in since it seems there are built-in's to find the required alignment...

There are already functions to convert bytes into integers and then floats, so all you need to write is a loop.

1 Like

FYI it's complicated but mostly yes

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.