在联合中设置字段位的最佳方法

Best way to set bits of fields in union

假设我有以下

struct S {
union {
    uint8_t flags;
    struct {
        uint8_t flag2bits : 2;
        uint8_t flag1bit : 1;
    };
};
};

S s;
s.flag2bits = 2;
s.flag1bit = 1; // this will wipe out the values of other bits

在不影响其他位字段的情况下为特定位赋值的最佳方法是什么?

我可以四处移动,然后赋值,然后再次移动,但这意味着一旦有人改变了位字段的顺序,代码就被破坏了....

C++ 编译器将为您管理位。您可以直接设置值。只会设置适当的位。

你尝试了吗?

I can shift around and then assign and then shift again but it means once someone changes the order of the bit fields, the code is broken....

不,这并不意味着代码已损坏。您可以根据需要更改位域(在任何 order/you 中可以保留其中一些未设置)

在你的例子中:

S s;
s.flag2bits = 2;
s.flag1bit = 1;

更改 flag2bits 不会影响存储在 flag1bit 中的值。

但是,您的问题可能与您在 struct 中持有的 union 有关。更改 flags 变量 影响两个位域,因为您将它们存储在单独的 struct 中。

我希望这个例子能解释这里的情况:

#include <iostream>
#include <cstdint>
struct S {
    union {
        uint8_t flags;
        struct {
            uint8_t flag2bits : 2;
            uint8_t flag1bit : 1;
        };
    };
};

int main(int argc, char *argv[]) {
    S s;
    s.flag2bits = 2;
    s.flag1bit = 1;

    std::cout << int(s.flag2bits) << int(s.flag1bit) << std::endl;
    s.flags = 4;  // As you are using union, at this point you are overwriting
                  // values stored in your (nested) struct
    std::cout << int(s.flag2bits) << int(s.flag1bit) << std::endl;

    return 0;
}

编辑: 正如@M.M 指出的那样,it's undefined behavior to read from the member of the union that wasn't most recently written。尽管至少在 clang-3.5 上,上面的代码会打印:

21
01

这说明了我要表达的观点(即覆盖联合字段)。

我会考虑从您的 struct S 代码中删除 union,但我可能看不到您要实现的目标的全貌。