考虑到评论中给出的限制(只关心Windows和Linux上的VC++和gcc),并且假设你愿意进一步限制为“在x86和ARM上运行”,那么你可以通过漂亮容易通过添加pragma
确保防止结构填充:
#pragma pack(push, 1)
struct Colour
{
uint8_t A;
uint8_t R;
uint8_t G;
uint8_t B;
};
#pragma pack(pop)
需要注意的是,如果你不关心与VC++的兼容性,您可能希望以不同的方式做到这一点(GCC/G ++有__attribute__(aligned(1))
,否则可能会是首选)。
就reinterpret_cast
而言,有一个相当简单的规则:操作数和目标类型必须始终是指针或引用(嗯,你可以传递一个glvalue的名字,但是使用的是对对象) - 这里的整个想法是获取引用原始对象的东西,但将它视为不同类型的“视图”,要做到这一点,必须传递可以访问操作数的内容,而不是只是它的价值。
如果您想要的结果是一个值(而不是参考或指针),则可以取消引用结果,并将该解除引用的结果分配给目标。
uint32_t value = *reinterpret_cast<uint32_t *>(&some_color_object);
或:
color c = *reinterpret_cast<Color *>(&some_uint32_t);
鉴于引用的性质,有可能为一些本应隐藏:
下面是测试代码的快速位做一些转换并测试/显示结果(使用指针和参考,无论值得多少):
#include <iostream>
#include <cassert>
#pragma pack(push, 1)
struct Colour
{
uint8_t A;
uint8_t R;
uint8_t G;
uint8_t B;
bool operator==(Colour const &e) const {
return A == e.A && R == e.R && G == e.G && B == e.B;
}
friend std::ostream &operator<<(std::ostream &os, Colour const &c) {
return os << std::hex << (int)c.A << "\t" << (int)c.R << "\t" << (int)c.G << "\t" << (int)c.B;
}
};
#pragma pack(pop)
int main() {
Colour c{ 1,2,3,4 };
uint32_t x = *reinterpret_cast<uint32_t *>(&c);
uint32_t y = 0x12345678;
Colour d = *reinterpret_cast<Colour *>(&y);
Colour e = reinterpret_cast<Colour &>(y);
assert(d == e);
std::cout << d << "\n";
}
请注意上面给出的限制。我已经用VC++(2015)和g ++(5.3)测试过了,我猜测它可能适用于这些编译器的其他版本 - 但是用这种代码保证的方式没有太多的东西。
它也完全有可能会与这些编译器发生冲突,但在不同的CPU上。特别是,您的Colour
和uint32_t
的对齐要求可能不同,因此在具有对齐要求的CPU上,它可能不起作用(甚至在Intel上,对齐可能会影响速度)。
这是未定义的行为。 (即使我们使用'union'也是UB。) – AlexD
“bitshifting workaround”是正确的方法 –
非常相关http://stackoverflow.com/questions/25734477/type-casting-struct-to-integer- c OMG @MM那里有你的答案:O – 101010