1

I have a question really similar to this: Building a 32-bit float out of its 4 composite bytes. Specifically I have an array of unsigned char composed by 8 elements:

unsigned char c[8] = {0b01001000, 0b11100001, 0b00100110, 0b01000001, 0b01111011,0b00010100, 0b10000110, 0b01000000}

This, with a little endianness convention corresponds to two floats, namely { 10.4300f, 4.19000f }.

I know that I could obtain the latter with:

float f[2];
memcpy(&f, &c, sizeof(f))

//f = { 10.4300f, 4.19000f }

But this involves, a copy. Is there a way to cast the c array inplace, changing its type so that I can avoid copying?

1 Answers1

1

Is there a way to cast the c array inplace

No. However, if the array is sufficiently aligned to hold a float, what you can do after memcpy is to placement-new a copy of that float onto the array.

Optimisers are smart, and typically know that you copied same value back. Sometimes two copies for abstract machine results in zero copies for cpu.

This, with a little endianness convention corresponds

I know that I could obtain the latter with

Note that memcpy will always result in native byte order and thus you only get little endian result on little endian systems. Thus the assumption of the data being interpreted as little endian is not a portable assumption.

If you want to avoid assuming native endianness, you'll need to read bytes in correct order, shift / mask them into an unsigned integer, then memcpy (or bit_cast) that integer into float.

eerorika
  • 181,943
  • 10
  • 144
  • 256
  • Thank you for your answer, how could ideally be checked that the optimizer abstract the copies and hence makes the operation inplace? – Tommaso Bendinelli Oct 16 '20 at 11:19
  • @TommasoBendinelli You can inspect the assembly. Just checking whether the call to memcpy has been removed or not is probably a decent heuristic for a quick check. – eerorika Oct 16 '20 at 11:23
  • Alright, thank you. So using memcpy is the correct pattern anyway, when dealing with such problems. – Tommaso Bendinelli Oct 16 '20 at 12:00
  • Unfortunately, the optimizers in clang and gcc sometimes omit operations that write storage with bit patterns it already held, *even when the write should have changed the type associated with that storage*. This behavior was reported as a bug years ago, but so far as I can tell, still remains in current versions of both compilers. I wonder if the authors of clang and gcc view the fact that the Standard allows objects' types to be changed by writing bit patterns that might match previously-held ones as a defect in the Standard, and thus view their compilers' behavior as just fine? – supercat Oct 20 '20 at 20:00