如何将位域成员的所有位设置为1

时间:2017-02-13 10:44:10

标签: c++ c++11

问题很简单。鉴于

struct Foo{
    bool     : 1;
    bool     : 1;
    int bar  : sizeof(int) * 8 - 2;
};

如何在没有警告的情况下将bar的所有位设置为1?

显然我可以做auto v = Foo(); v.bar = ~0;但是GCC给了我这个:

warning: large integer implicitly truncated to unsigned type [-Woverflow]

我尝试了几种方法,但它总是会发出警告......

2 个答案:

答案 0 :(得分:2)

请勿使用~0(始终为完整int),~v.bar,这是正确的尺寸,可以像这样组合使用:

v.bar |= ~v.bar; // or,
v.bar ^= ~v.bar;

应该做任何规模的技巧。

不幸的是,由于无法绑定对位域的引用,因此无法很好地将其包装在函数中。您需要在Foo&上创建一个函数,或使用宏。

PS。我在使用coliru发布之前快速尝试了这一点,并在本地使用GCC(g ++)5.3.1和6.2.0进行了重新检查 - 都没有使用-Wall发出任何诊断。

PPS。

使用此测试代码,GCC仅为未签名成员生成诊断:

struct Foo {
  int i : 2;
  unsigned int u : 30;
};

void bar() {
  Foo f {0, 0};
  f.i ^= ~f.i; // OK
  f.u |= ~f.u; /* warning:
    large integer implicitly truncated to unsigned type [-Woverflow]
  */
}

因此,虽然我通常也喜欢无符号整数用于位域或按位操作,但g ++在这里使用int更快乐更安静。

答案 1 :(得分:1)

这适用于无符号类型。请注意,除非您对未定义的行为感到满意,否则应使用无符号类型完成所有的位操作。

...
   unsigned int bar  : sizeof(int) * 8 - 2;
...

template <typename T, unsigned n>
constexpr T onebits()
{
    return 1 | (((1 << (n-2)) - 1) << 1);
}

v.bar = onebits<unsigned, sizeof(int) * 8 - 2>();