Arduino:工会中的结构顺序
Arduino: struct order in unions
我有这个代码:
typedef union {
struct {
unsigned long red:8;
unsigned long green:8;
unsigned long blue:8;
};
struct {
unsigned long r:8;
unsigned long g:8;
unsigned long b:8;
};
unsigned long hex;
} UniColor;
我的想法是自动使用十六进制代码作为RGB颜色。例如:
UniColor color;
color.hex = 0xFF0000; // Red
Serial.println(color.red); // I hope that it prints 255.
Serial.println(color.green); // I hope that it prints 0.
Serial.println(color.blue); // I hope that it prints 0.
但是当它打印时:
0
0
255
我做了很多测试,得出的结论是它的结构顺序颠倒了。它是 BGR insted RGB。我试图改变结构的顺序,但它不起作用。最糟糕的是,使用 gcc 编译器可以正常工作:
typedef union {
struct {
unsigned blue:8;
unsigned green:8;
unsigned red:8;
};
struct {
unsigned b:8;
unsigned g:8;
unsigned r:8;
};
unsigned hex:24;
} UniColor;
...
UniColor color;
color.hex = 0xff0000;
cout << color.red << endl; // 255
cout << color.green << endl; // 0
cout << color.blue << endl; // 0
我该怎么做才能让它发挥作用?
首先,如注释中所述,类型双关在 C++ 中是未定义的行为。因此,您应该只读取上次为其赋值的联合成员。第二个问题是位字段的填充顺序是实现定义的(一些编译器可能会将第一个成员放在基础类型的 MSB 上,但大多数人更喜欢 LSB)。
为了解决这些问题中的任何一个,我会完成您尝试使用位域手动简化的工作:
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
(u:未使用);如果您喜欢或需要不同的顺序,请在上述函数中适当调整位移位。您甚至可以考虑将到目前为止未使用的字节用于 alpha 通道...
最后,经过研究我还没有找到 easy/universal 反转位域的方法。我选择创建一个 class 来有效地分配字段:
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];
}
};
有效。它比没有方法的简单结构更重,但正如我们在西班牙所说:没有带刺的玫瑰。
我有这个代码:
typedef union {
struct {
unsigned long red:8;
unsigned long green:8;
unsigned long blue:8;
};
struct {
unsigned long r:8;
unsigned long g:8;
unsigned long b:8;
};
unsigned long hex;
} UniColor;
我的想法是自动使用十六进制代码作为RGB颜色。例如:
UniColor color;
color.hex = 0xFF0000; // Red
Serial.println(color.red); // I hope that it prints 255.
Serial.println(color.green); // I hope that it prints 0.
Serial.println(color.blue); // I hope that it prints 0.
但是当它打印时:
0
0
255
我做了很多测试,得出的结论是它的结构顺序颠倒了。它是 BGR insted RGB。我试图改变结构的顺序,但它不起作用。最糟糕的是,使用 gcc 编译器可以正常工作:
typedef union {
struct {
unsigned blue:8;
unsigned green:8;
unsigned red:8;
};
struct {
unsigned b:8;
unsigned g:8;
unsigned r:8;
};
unsigned hex:24;
} UniColor;
...
UniColor color;
color.hex = 0xff0000;
cout << color.red << endl; // 255
cout << color.green << endl; // 0
cout << color.blue << endl; // 0
我该怎么做才能让它发挥作用?
首先,如注释中所述,类型双关在 C++ 中是未定义的行为。因此,您应该只读取上次为其赋值的联合成员。第二个问题是位字段的填充顺序是实现定义的(一些编译器可能会将第一个成员放在基础类型的 MSB 上,但大多数人更喜欢 LSB)。
为了解决这些问题中的任何一个,我会完成您尝试使用位域手动简化的工作:
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
(u:未使用);如果您喜欢或需要不同的顺序,请在上述函数中适当调整位移位。您甚至可以考虑将到目前为止未使用的字节用于 alpha 通道...
最后,经过研究我还没有找到 easy/universal 反转位域的方法。我选择创建一个 class 来有效地分配字段:
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];
}
};
有效。它比没有方法的简单结构更重,但正如我们在西班牙所说:没有带刺的玫瑰。