Method 1
Problem 1: struct1->hex1
, struct1->hext2
, struct->num1
, and struct1->num2
access the memory of data
, which has effective type uint8_t
(which is likely a character type), but they access that memory with a structure type. The behavior of this is undefined because it does not conform to the aliasing rules in C 20186 6.5 7:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types: …
(There is a complication here in that the aliasing rules allow “an aggregate or union type that includes one of the aforementioned types among its members,” but I would not expect the nominal use of uint8_t
in declaring the bit-field members satisfy that.)
This problem might be fixed by changing RandomStruct *struct1 = (RandomStruct *)data;
to RandomStruct struct1;
, using memcpy(&struct1, data, sizeof struct1);
and changing the subsequent struct1->
occurrences to struct1.
.
Problem 2: The C standard does not specify the order in which hex2
and hex1
are located in the storage unit used to hold them, per C 2018 6.7.2.1 11:
… The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined…
Note that the order of allocation of bit-fields is not determined by the endianness of the C implementation. Regardless of whether a C implementation puts low-significance bytes of integer types earlier in memory or later in memory, it may place the first bit-field of a structure in the low bits of the storage unit or in the high bits of the storage unit.
This cannot be fixed portably in C (that is, using only strictly conforming code); you must ensure the members are declared in the necessary order for each C implementation you use.
Problem 3: The two bit-fields of the structure do not necessarily occupy just one byte. C 2018 6.7.2.1 11 says:
An implementation may allocate any addressable storage unit large enough to hold a bit-field…
This is a separate issue from packing the structure, as the storage unit used for bit-fields would be considered as bytes used for the bit-fields, not padding bytes that are eliminated by packing.
This cannot be fixed portably in C but a violation of the desired layout could be detected with _Static_assert(sizeof (RandomStruct) == 5, "Error, expected just five bytes in RandomStruct.");
.
Method 2
Problem 1: data[1] | (data[2] << 8)
is not guaranteed to work in every C implementation because data[2]
will be promoted to int
, and the C standard allows int
to be 16 bits. If the high bit of data[2]
is set, then data[2] << 8
would produce a result greater than or equal to 32,768, which is not representable in a 16-bit int
. Then overflow occurs, and the behavior is not defined by the C standard, per C 2018 6.5.7 4:
… If E1
has a signed type and nonnegative value, and E1
× 2E2
is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
This could be fixed by casting data[2]
to uint16_t
and similarly for data[4]
.