I have a situation in a legacy code with a large field of a structure being split into two sub-fields. For example, a uint32
is split into two uint16
's:
typedef struct
{
uint16 myVar_H;
uint16 myVar_L;
} MyStruct;
Until now these fields were read from a uint32
variable via shifting to read each uint16
portion. Now we want to optimize this so that we read the entire uint32
by casting the first field's address to a uint32
:
MyStruct s;
*((uint32*)(&s.myVar_H)) = myValue;
This works for my compiler. The question is if this is legal and defined in C89 (or other C standards)?
Note: changing the structure is another option, but since this is an ancient legacy code based on a proprietary protocol I'd rather not touch the structures definition.
Edit: I am using a big-endian MCU (a ColdFire), so this works correctly in the endianess regard.
There's a few problems with your "optimized" solution:
myVar_H
and myVar_L
are consecutive in memory: the compiler is allowed to add padding between the two fields.The legal and platform-independant way of achieving what you want is to keep your previous solution with shifting. It shouldn't bring any performance issues.
MyStruct s;
// Reading
uint32 u = (uint32)s.myVar_H << 16 | s.myVar_L; // The cast is important
// Writing
s.myVar_H = myValue >> 16;
s.myVar_L = myValue % 0xFFFF;
Edit following comment: you say you work on big endian machines so memory order is not a problem. In that case, the "most legal" thing you may do is make your struct a union
with an anonymous struct (not actual C89
, it's a gcc
extension). This way you don't break strict aliasing and the new definition doesn't break any existing code.
typedef union // Your type is now a union
{
struct
{
uint16 myVar_H;
uint16 myVar_L;
}; // Anonymous struct, legal C11 but gcc extension in C89
uint32 myVar;
} MyStruct;
s.myVar = myValue; // Safe