Strict aliasing warning, creating uint32_t reference to unsigned char array + offset

徘徊边缘 提交于 2019-12-07 17:45:20

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!