问题
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
回答1:
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.
回答2:
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
.
回答3:
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