tl; dr位操作是否安全,並且在整數提升時的預期行爲(類型短於int
)?使用整數提升的位操作
例如
uint8_t a, b, c;
a = b & ~c;
這是什麼,我有一個粗略的MCVE:
struct X { // this is actually templated
using U = unsigned; // U is actually a dependent name and can change
U value;
};
template <bool B> auto foo(X x1, X x2) -> X
{
if (B)
return {x1.value | x2.value};
else
return {x1.value & ~x2.value};
}
這個偉大的工程,但是當U
變更爲整型短於int
,例如std::uint8_t
則由於整型的提升,我得到一個警告:
警告:縮小的「(INT)轉換(((無符號 字符)((int)的x1.X ::值))|((無符號字符)((int)的x2.X ::值)))」從 'INT' 爲 'X ::∪{又名無符號字符}' 內{} [-Wnarrowing]
所以我添加一個static_cast
:
struct X {
using U = std::uint8_t;
U value;
};
template <bool B> auto foo(X x1, X x2) -> X
{
if (B)
return {static_cast<X::U>(x1.value | x2.value)};
else
return {static_cast<X::U>(x1.value & ~x2.value)};
}
問題:能否整數提升,然後narro翼投與預期結果(*)混亂?特別是因爲這些是演員改變簽名的前後(unsigned char
- >int
- >unsigned char
)。如果U
已簽名,那麼怎麼辦?std::int8_t
(它不會在我的代碼中籤名,但會對此行爲感到好奇)。
我常見的sens說代碼完全正常,但是我的C++偏執狂說至少有一個實現定義行爲的機會。
(*)是它的不明確的情況下(或I弄亂)的預期行爲是設置或清除位(x1
是值,x2
是掩模,B
是設置/清除操作)
(簽訂目標):這些位操作的情況下,我認爲任何結果可以表示回目標類型,從而避免實現定義的行爲。我對麼? – bolov
在所有*正常*架構中,你是對的。我想知道什麼可能會破壞那個('int8_t'是兩個補碼,但是普通的'int'不是),並且如果這可以按照標準被允許的話。現在我沒有明確的答案... –
@bolov:我已經深入瞭解標準,並且沒有任何東西禁止一個實現支持'int8_t'類型,但是使用*符號和幅度*來獲得普通的'int'。在這種情況下'((int8_t)-128)| (int8_t)1'可以給'-129'應用積分促銷(轉換爲int)。因此,沒有什麼能保證按位操作對簽名類型是穩定的(導致與操作數類型相同)。 –