具有匿名结构的不同位映射

时间:2017-05-19 14:28:28

标签: c++ struct unions anonymous-struct

我想为一些位实现不同的映射。 我提出了这个对我合理的解决方案:

union myBits{
 // constructors

 struct{ // Mapping 1
   uint16_t a : 8, b : 8;
 };
 struct{ // Mapping 2
   uint16_t c : 10, d : 6;
 };
};

然后我可以通过

访问不同的位映射
myBits mb(/**/);
mb.c = 10;
mb.a = 2;

我认为这个功能非常优雅,虽然它不被认为是标准的C ++。 g ++和clang产生警告(告诉我标准中不允许匿名结构),Visual Studio编译代码而不产生任何警告。

我的问题是:是否有一种现代C ++ 1x编写相同代码的方法,其功能相同,不仅仅包含命名结构?

1 个答案:

答案 0 :(得分:2)

由于C ++与C相比存在约束,我认为在标准C ++中没有任何有效,合法和优雅的方法。您只能选择三个属性中的两个:)

高效合法,但不优雅

struct myBits
{
    void set_bits(size_t start_bit, size_t end_bit, uint16_t value)
    {
        size_t len = end_bit - start_bit + 1;
        uint16_t mask = ((1 << len) - 1) << (start_bit - 1);
        word = (word & ~mask) | ((value << (start_bit - 1)) & mask);
    }
    uint16_t get_bits(size_t start_bit, size_t end_bit)
    {
        size_t len = end_bit - start_bit + 1;
        return (word >> (start_bit - 1)) & ((1 << len) - 1);
    }
    uint16_t word;
};

像在你的场景中一样使用它:

myBits mb;
mb.set_bits(1, 10, 10);
mb.set_bits(1, 8, 2);

这可能不是真正和问题中的代码一样高效,它实际上取决于编译器如何生成访问位字段的代码与上面的代码。与初始解决方案相比,它的优点是您可以访问任何位子集,而无需为其定义新的结构和位域。

合法而优雅,但效率不高

template<size_t start_bit, size_t end_bit>
struct bit_field
{
    bit_field(uint16_t& w) : word(w) {}

    operator uint16_t() const
    {
        return (word >> (start_bit - 1)) & ((1 << len) - 1);
    }

    bit_field& operator=(uint16_t value)
    {
        uint16_t mask = ((1 << len) - 1) << (start_bit - 1);
        word = (word & ~mask) | ((value << (start_bit - 1)) & mask);
        return *this;
    }

    const size_t len = end_bit - start_bit + 1;
    uint16_t &word;
};

struct Word
{
    Word(uint16_t w) : word(w), a(word), b(word), c(word), d(word) {}

    uint16_t word;
    bit_field<1, 8> a;
    bit_field<9, 16> b;
    bit_field<1, 10> c;
    bit_field<11, 16> d;
};

在这种情况下的用法与示例中的一样优雅:

Word w(0);
w.c = 10;
w.a = 2;

这种方法的问题在于它实际上是空间效率低下的。与仅存储位的初始方法相比,您必须为每个位字段声明一个结构。

高效优雅,但不合法

这基本上就是你在问题中描述的方式。