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

有效。它比没有方法的简单结构更重,但正如我们在西班牙所说:没有带刺的玫瑰