严格别名警告,创建uint32_t对unsigned char array + offset的引用

时间:2012-07-01 14:46:04

标签: c++ c++11 g++ gcc-warning

使用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;

据我了解,您可以将任何数据转换为charunsigned char,这是允许的,但这只能以一种方式运行。

一种解决方案是制作union。是否有其他方法可以为unsigned char数据创建不同类型的引用?

谢谢! 大卫

3 个答案:

答案 0 :(得分:4)

是的,允许将数据视为char或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);

另一种方法是将有效负载创建为具有适当大小和成员的标准布局类型,然后将其作为unsigned 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);

这并没有违反严格的别名规则,因为它现在正朝着正确的方向发展。

答案 1 :(得分:1)

联盟也将是未定义的行为。您只能在这方面使用char - 不允许使用其他类型,其中包括unsigned char

答案 2 :(得分:1)

您可以做的是创建一个uint32_t数组。这样您就可以uint32_t访问它们,也可以unsigned char访问它们:这不会违反别名规则。