2017-02-13 28 views
2

问题很简单。给定如何设置位域成员的所有位为1

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] 

我已经尝试了几种方法,但它总是呈现一个警告...

+1

为什么你需要一个位场? (顺便说一下,不能保证你的结构不会包含太多的bool和int)。 – StoryTeller

+0

M.b.你可以使用memset()? – voltento

+0

'v.bar = UINT_MAX;'是什么? –

回答

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] 
    */ 
} 

所以,虽然我还通常喜欢的无符号整数为位域或按位操作,克++是快乐和安静与int这里。

+0

从6.0.1开始,'g ++'仍然对这些结构提出警告('gcc'不)。 –

+0

'铿锵3.8'不会警告 – olgierdh

+0

注意:'Foo v; v.bar | =〜v.bar;'会因为使用未初始化的变量而成为UB。该代码依赖于之前已经初始化的'v.bar',就像OP代码中那样。如果你知道它是零初始化的,那么'v.bar =〜v.bar;'就足够了。 –

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>(); 
+0

这非常整齐,谢谢你的贡献! –