我有这个代码:
typedef union { struct { unsigned long red:8; unsigned long green:8; 无符号长蓝:8; }; struct { 无符号长r:8; 无符号长g:8; 未签名……
最后,在研究之后,我还没有找到一种简单/通用的方法来反转位域。我选择创建一个类来有效地分配字段:
class RGBColor { public: union{ struct { unsigned blue:8; unsigned green:8; unsigned red:8; }; struct { unsigned b:8; unsigned g:8; unsigned r:8; }; unsigned long hex:24; }; RGBColor(unsigned _r, unsigned _g, unsigned _b) : r(_r), g(_g), b(_b) {}; RGBColor(unsigned _hex = 0x000000) : hex(_hex) {}; void operator=(unsigned _hex) { hex = _hex; } void operator=(unsigned a[3]) { r = a[0]; g = a[1]; b = a[2]; } };
有用。它比没有方法的简单结构更重,但正如我们在西班牙所说: 没有荆棘就没有玫瑰 。
首先,如注释中所示,类型punning是C ++中未定义的行为。因此,您应该只读取上次为其分配值的union成员。第二个问题是填充位字段的顺序是实现定义的(一些编译器可能将第一个成员放在底层类型的MSB上,但大多数人更喜欢LSB)。
为了解决这些问题,我会尝试手动简化bitfields的工作:
class UniColor { uint32_t color; // defined in cstdint header; safer than unsigned long or int! public: UniColor(uint32_t color) : color(color) { } UniColor(uint8_t red, uint8_t green, uint8_t blue) : color ( static_cast<uint32_t>(red) << 16 | static_cast<uint32_t>(green) << 8 | static_cast<uint32_t>(blue) ) { } uint8_t red() // getter { return color >> 16; } void red(uint8_t value) // setter { color = color & 0x0000ffffU | static_cast<uint32_t>(red) << 16 } uint8_t green() { return color >> 8 & 0xffU; } // rest analogously };
您会注意到我将32位设置为 0xuurrggbb (你:未使用过);如果您更喜欢或需要不同的订单,请在上述功能中适当调整位移。您甚至可以考虑使用到目前为止未使用的字节用于Alpha通道...
0xuurrggbb