C & C++ DISCUSSION

What is the strict aliasing rule in C, and how do I safely read a float from a byte buffer?

Started by archer09 strict aliasingtype punningmemcpyunaligned accessbyte buffer parsing
4 replies 248 views 5 participants
Latest activity · 30 Sep 2026

What is the strict aliasing rule in C, and how do I safely read a float from a byte buffer?

archer09 C & C++ Forum
#1

My UART receive buffer is uint8_t rx[64], and a packet carries a 32-bit float at offset 3. I read it with float v = *(float *)&rx[3];. It has worked for months on a Cortex-M4, but a colleague says the cast breaks the strict aliasing rule, and on a Cortex-M0 board the same line ends in a HardFault.

What exactly is the rule being broken, and what is the correct, portable way to pull typed values out of a byte buffer?

Community replies 4

Re: What is the strict aliasing rule in C, and how do I safely read a float from a byte buffer?

#2

The rule says an object may only be accessed through an lvalue of its own type, a qualified or signed/unsigned variant of that type, or a character type. Your storage is an array of uint8_t; reading it through a float lvalue is none of those, so the behaviour is undefined.

The rule lets the optimiser assume that a float * and an int * never point at the same memory, so it can keep values in registers across stores through the other pointer. The exception runs in one direction only: any object may be inspected through unsigned char *, but a char array may not be inspected through some other type.

Re: What is the strict aliasing rule in C, and how do I safely read a float from a byte buffer?

#3

The portable fix is memcpy: float v; memcpy(&v, &rx[3], sizeof v);. It is fully defined, and with optimisation enabled GCC and Clang recognise a small fixed-size copy and emit plain load instructions instead of a library call.

It also cures your HardFault, which is an alignment problem rather than an aliasing one. Offset 3 is not a multiple of 4, and the Cortex-M0 (ARMv6-M) does not support unaligned word access, so a direct 32-bit load from that address faults. Cortex-M3 and M4 tolerate unaligned loads for most instructions, which is why the bug stayed hidden on the first board.

Re: What is the strict aliasing rule in C, and how do I safely read a float from a byte buffer?

#4

A union is the other accepted method in C: union { uint8_t b[4]; float f; } u;, copy four bytes into u.b and read u.f. C permits reading a member other than the one last written. C++ does not, so there use memcpy or std::bit_cast from C++20.

Mind the byte order as well. memcpy reproduces the bytes as they sit in the buffer. If the protocol is big-endian and the MCU little-endian, assemble an integer first: uint32_t u = ((uint32_t)rx[3] << 24) | ((uint32_t)rx[4] << 16) | ((uint32_t)rx[5] << 8) | rx[6]; and then memcpy that into the float. The shift form does not depend on the CPU's endianness or alignment.

Re: What is the strict aliasing rule in C, and how do I safely read a float from a byte buffer?

#5

A small example shows how the optimiser uses the rule: int f(int *i, float *p) { *i = 1; *p = 0.0f; return *i; }. At -O2 the compiler may return the constant 1 without re-reading *i, because a store to a float is assumed not to change an int. Call it with both pointers aimed at the same memory and it returns 1 while the memory holds 0.

GCC and Clang enable this at -O2; -fno-strict-aliasing switches it off and is a reasonable safety net for legacy code, but it is a compiler dialect, not a fix. Casting the buffer to a struct pointer, (struct header *)rx, has the same aliasing and alignment problems plus padding, so copy into a local struct or parse field by field.

TEP COMMUNITY