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
より短い整数型に変更されたとき
警告::|((unsigned char型「(int型)(((符号なし 文字)((int型)x1.X ::値))の変換を狭め、その後原因私は警告を受ける整数プロモーションへ
std::uint8_t
INT「 から 'X' に ')((INT)x2.X ::値)))::内部U {別名unsigned char型は} {} [-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)};
}
質問:整数プロモーションとナルロ意図した結果(*)で翼キャスト混乱?特にこれらはキャストであるため、符号の前後を変更する(unsigned char
- >int
->unsigned char
)。 U
が署名されている場合、つまりstd::int8_t
(これは自分のコードでは署名されませんが、そのような場合は動作が不明です)。
私の常識は、コードは完全にOKだと言いますが、私のC++のパラノイアは、少なくとも実装定義の動作の可能性があると言います。
(*)の場合であることははっきりしていない(または私はめちゃめちゃに)意図した動作は(B
をセット/クリアオペアンプで、x2
がマスクされ、x1
が値である)ビットを設定またはクリアすることです
(署名された対象):このビット操作の場合には、私は、任意の結果は、このように、バック先の型に表現することができると思うだろう実装定義の振る舞いを避ける。私は正しいですか? – bolov
すべての* normal *アーキテクチャであなたは正しいです。 (int8_tは2の補数ですが、普通はintではありません)、それが標準で許されるのかどうかは分かりません。今のところ、私はそれに決定的な答えはありません... –
@bolov:私は標準を掘り下げ、 'int8_t'型をサポートするインプリメンテーションを禁じますが、* signとmagnitude *を使って単純なintを持っていません。その場合、 '((int8_t)-128)| (int8_t)1'は '-129'を与えることができます。積分プロモーション(intへの変換)が適用されます。したがって、符号付きの型のビット演算が安定している(オペランドと同じ型になります)ことは何も保証されていません。 –