工作中的代码库包含一些看起来大致如下的代码:
#define DATA_LENGTH 64
u_int32 SmartKey::SerialNumber()
{
unsigned char data[DATA_LENGTH];
// ... initialized data buffer
return *(u_int32*)data;
}
此代码可正常运行,但GCC会发出以下警告:
warning: dereferencing pointer ‘serialNumber’ does break strict-aliasing rules
有人可以解释这个警告吗?这个代码有潜在危险吗?如何改进?
更新的
感谢James McNellis的回答,我提出了以下效用函数:
template<class T, class Data>
T BinaryCast(const Data & inData)
{
T ret;
std::copy(&inData[0], &inData[0] + sizeof(ret), reinterpret_cast<char*>(&ret));
return ret;
}
u_int32 SmartKey::SerialNumber()
{
unsigned char data[DATA_LENGTH];
// ... initialized data buffer
return BinaryCast<u_int32>(data);
}
随意提出改进建议!
答案 0 :(得分:11)
警告是因为您违反了strict aliasing rule。
正确执行此操作的一种方法是将data
缓冲区中的字节复制到u_int32
对象中并返回该对象:
unsigned char data[DATA_LENGTH];
// ... initialized data buffer
u_int32 i;
assert(sizeof (i) <= DATA_LENGTH);
std::copy(&data[0], &data[0] + sizeof (i), reinterpret_cast<char*>(&i));
return i;
此解决方案有效,因为在C ++中,允许以char
数组的形式访问任何类型的对象。
(std::copy()
位于<algorithm>
)
答案 1 :(得分:2)
在C和C ++语言中,将一种类型的对象占用的内存重新解释为另一种类型的对象是非法的 - 它会导致未定义的行为。某些编译器使用此规则来执行积极的与别名相关的优化。因此,如果执行上述重新解释,您的代码可能无法按预期工作。
在C / C ++中,可以将任何对象重新解释为char数组,但是不能单独使用char数组并重新解释为某种其他类型的对象。这就是你的代码正在做的事情。
除了别名问题之外,您还必须记住,不能保证独立的自动字符数组能够正确对齐以便作为u_int32
值读取。
执行上述代码尝试执行的操作的正确方法是使用u_int32
memcpy
值
u_int32 SmartKey::SerialNumber()
{
unsigned char data[DATA_LENGTH];
u_int32 u;
// ...
memcpy(&u, data, sizeof u);
return u;
}
当然,您必须确保数据的字节顺序与平台上u_int32
个对象的字节顺序相同。
答案 2 :(得分:0)
我认为问题实际上是在你的elided代码中的某个地方初始化data []结构。我不认为这与你的演员有任何关系,这很好。
答案 3 :(得分:-1)
不确定,但我认为你可以这样做:
return (u_int32)&data;