在GNU GCC 4.7.0+中,我得到了一些严格的混叠警告,我想解决。
我有一个有效负载(来自硬件):
unsigned char payload[davidlt::PAYLOAD_SIZE];
我有这样一句话:
*(uint32_t*)(payload + davidlt::DATA_OFFSET) = (pid & davidlt::PID_MASK) << davidlt::PID_SHIFT;
这将创建一个指向有效负载中特定位置的指针,并将 4 个字节解释为 uint32_t
。将计算新值uint32_t
类型并在有效负载中替换。
我得到:
warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
我希望通过使用reinterpret_cast
来解决它,但我得到了同样的警告。
*reinterpret_cast<uint32_t *>(payload + davidlt::DATA_OFFSET) = (pid & davidlt::PID_MASK) << davidlt::PID_SHIFT;
据我了解,您可以将任何数据转换为char
或unsigned char
,这是允许的,但这只能以一种方式工作。
一种解决方案是 做一个 union
.不是有任何其他方法可以创建不同类型的引用来unsigned char
数据吗?
谢谢!大卫
是的,允许将数据视为字符或无符号字符,但反之则不然。
相反,在这种情况下,您应该使用memcpy。您的行采用pid
值,对其进行屏蔽、移动,然后将其插入有效负载。对此的直接翻译是:
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);
另一种方法是将有效负载创建为具有适当大小和成员的标准布局类型,然后将其视为无符号 char 数组。假设您可以控制创建有效负载:
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);
这并不违反严格的别名规则,因为它现在正朝着正确的方向发展。
联合也将是未定义的行为。您只能在这方面使用char
- 不允许使用其他类型,其中包括unsigned char
。
您可以做的是创建一个uint32_t
数组。这样,您可以uint32_t
访问它们,也可以unsigned char
:这不违反别名规则。