With GNU GCC 4.7.0+ I got a few strict aliasing warnings, which I would like to resolve.
I have a payload (from hardware):
unsigned char payload[davidlt::PAYLOAD_SIZE];
I had this line:
*(uint32_t*)(payload + davidlt::DATA_OFFSET) = (pid & davidlt::PID_MASK) << davidlt::PID_SHIFT;
This creates a pointer to a specific location in payload and 4 bytes are interpreted as uint32_t
. A new value uint32_t
type is calculated and replaced in the payload.
I get:
warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
I was hoping to solve it by using reinterpret_cast
, but I get the same warning.
*reinterpret_cast<uint32_t *>(payload + davidlt::DATA_OFFSET) = (pid & davidlt::PID_MASK) << davidlt::PID_SHIFT;
As I understood you can convert whatever data to char
or unsigned char
, which is allowed, but that works only one way.
One solution would be to make a union
. Aren't were any other way to create a reference of different type to unsigned char
data?
Thanks! david
Yes, viewing data as char or unsigned char is allowed, but not the reverse.
Instead you should use memcpy in this case. Your line takes a pid
value, masks it, shifts it, and then inserts it into the payload. A direct translation of this would be:
unsigned char payload[davidlt::PAYLOAD_SIZE];
uint32_t payload_pid = (pid & davidlt::PID_MASK) << davidlt::PID_SHIFT;
std::memcpy(payload + davidlt::DATA_OFFSET, &payload_pid, sizeof payload_pid);
Another alternative would be to create your payload as a standard layout type with the appropriate size and members, and then to view it as an unsigned char array. Assuming you're in control of creating the payload:
struct Payload {
...
uint32_t pid;
...
} payload;
payload.pid = (pid & davidlt::PID_MASK) << davidlt::PID_SHIFT;
static_assert(davidlt::PAYLOAD_SIZE == sizeof(Payload), "");
unsigned char (&payload_as_char)[davidlt::PAYLOAD_SIZE] = reinterpret_cast<unsigned char (&)[davidlt::PAYLOAD_SIZE]>(&payload);
This isn't violating the strict aliasing rule because it's going the right direction now.
The union would also be undefined behaviour. You can only use char
in this respect- no other type is allowed, and that includes unsigned char
.
What you can do is to create an array of uint32_t
instead. This way you could access them as uint32_t
but also as unsigned char
: this does not violate the aliasing rules.
来源:https://stackoverflow.com/questions/11282886/strict-aliasing-warning-creating-uint32-t-reference-to-unsigned-char-array-of