1

次のコードではオーバーフローが発生しますが、残念ながら理由がわかりません。

std::int8_t smallValue         = -1;
unsigned int value             = 500;
std::uint8_t anotherSmallValue = 1;

auto test = smallValue * value * anotherSmallValue;

その後testはかなり大きな値です。

ここで何が起こっているのか、誰か説明してもらえますか?

4

5 に答える 5

6

結果の型はunsigned int test hereになります。smallValue * value smallValueunsigned にキャストされるため、この式は(unsigned)-1 * 500. ただし、このコードを-Wsign-conversion- でコンパイルすると、悪いことをしていることがコンパイラに通知されます。リンク

于 2013-04-05T12:47:45.513 に答える
5

コンパイラはsmallValue * valueを確認すると、入力データ型signed(8 ビット) およびunsigned int(通常は 16 ビットまたは 32 ビット) を考慮して、結果のデータ型を決定する必要があります。C++ の規則では、この状況では結果が符号なしになると規定されています。したがって、期待どおり、 の値を にすることはsmallValue * valueできません。-500代わりに、値-500は正の数値として解釈されます。

さらに、ここでは 8 ビット値に通常 16 ビットまたは 32 ビットのいずれかの値を掛けています。このシナリオでの C++ の規則では、小さい方のストレージ値が最初に大きい方の値と同じサイズにキャストされると規定されています。したがって、この場合、 の結果smallValue * valueは確かに大きさの大きさを格納するのに十分な大きさになり500ます。

符号なしの量anotherSmallValue(=1)を乗算するunsignedと、同じ値の別の値が得られます。

を使用しているためauto、戻り値の型は と推定されますunsigned

にキャストバックするだけでsigned(たとえば、値testintではなくとして定義すると、通常は、内部でビットを変更することなくauto、操作全体の結果が値にキャストされます。これにより、 が適切に表示されます。ただし、他の投稿者が指摘しているように、これは理論的にはかなり危険です。これは、現在のコンパイラでは通常このように動作しますが、技術的に動作することが保証されていないためです。signed-500

于 2013-04-05T12:57:29.267 に答える
2

最初の 2 つの変数だけで同じ結果が得られます ( smallValue * value)。

最初に、整数昇格が両方の値に適用されます:int8_tになりintunsigned intそのまま残ります。

次に、C++11 5/9 の次のルールを適用して、結果の型を決定します。

それ以外の場合、符号なし整数型を持つオペランドのランクが他のオペランドの型のランク以上である場合、符号付き整数型を持つオペランドは、符号なし整数型を持つオペランドの型に変換されます。

したがって、剰余算術-1を使用するように変換する必要がありunsigned int、大きな正の数が得られます。500 を掛けるとオーバーフローし (再び剰余算術を使用)、異なる大きな数が得られます。

于 2013-04-05T12:55:21.333 に答える
1

「auto」を符号付きタイプにすると問題ありません。

long test = smallValue * value * anotherSmallValue;
于 2013-04-05T12:50:26.210 に答える
1

混合型を操作すると、常にこのようなエラーが発生しやすくなります。算術演算には単一の型を使用することをお勧めします

于 2013-04-05T12:56:00.547 に答える