2017-02-13 24 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

這非常整齊,謝謝你的貢獻! –