开发者

How to interpret binary data as an integer?

The codebase at work contains some code that looks roughly like this:

#define DATA_LENGTH 64

u_int32 SmartKey::SerialNumber()
{
    unsigned char data[DATA_LENGTH];
    // ... initialized data buffer
    return *(u_int32*)data;
}

This code works correctly, but GCC gives the f开发者_如何学Collowing warning:

warning: dereferencing pointer ‘serialNumber’ does break strict-aliasing rules

Can someone explain this warning? Is this code potentially dangerous? How can it be improved?

Update

With thanks to James McNellis' answer I came up with the following utility function:

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);
}

Feel free to suggest improvements!


The warning is because you are violating the strict aliasing rule.

One way to do it correctly would be to copy the bytes from the data buffer into a u_int32 object and return that object:

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;

This solution works because in C++ it is permitted to access any type of object as an array of char.

(std::copy() is in <algorithm>)


In C and C++ languages reinterpreting memory occupied by object of one type as an object of another type is illegal - it leads to undefined behavior. Some compilers use this rule to perform aggressive aliasing-related optimizations. As a consequence, your code might not work as expected, if you perform the aforementioned reinterpretation.

In C/C++ it is OK to reinterpret any object as an array of char, but it is not OK to take a standalone array of char and reinterpret is as an object of some other type. This is what your code is doing.

In addition to aliasing problems, you have to keep in mind that a standalone automatic char array is not guaranteed to be aligned properly to be read as an u_int32 value.

The proper way to do what the above code is trying to do is to copy the source array into an intermediate u_int32 value using memcpy

u_int32 SmartKey::SerialNumber()
{
    unsigned char data[DATA_LENGTH];
    u_int32 u;
    // ...
    memcpy(&u, data, sizeof u);
    return u;
}

Of course, you have to be sure that the endianness of the data is the same as the endianness of the u_int32 objects on your platform.


I think the problem is actually somewhere in your elided code to initialize the data[] structure. I don't think it has anything to do with your cast, which is fine.


Not sure, but I think you can do like that:

return (u_int32)&data;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜