0

私は奇妙なバグ/エラー/自己愚かさの懸念を持っています。私はCで小さなアプリケーションを開発しており、Visual Studio2010SP1を使用しています。問題のあるコード:

uint64_t sum_squared_X = 65535*65535*64;
int64_t sum_squared_Y = 65535*65535*64;

デバッグすると、次の結果が得られます。

sum_squared_X = 18446744073701163072;
sum_squared_Y = -8388544;

質問は、なぜですか?uint64_tの最大値は2^64-1または18446744073709551615であり、int64_tの最大値は2^63-1または9223372036854775807です。

65535 * 65535 * 64 = 274869518400、これは両方の最大値よりも低くなっています。では、なぜこれらの結果が得られるのでしょうか。

私はここで完全に迷子になっています、いくつかの助けをいただければ幸いです。

4

2 に答える 2

3

簡単な答え:65535に32-big符号付き演算を使用して65535を掛けると、-131,071が生成されます。次に、これに-64を掛けて、uint64_t(ラッピングにより大きな正の値を作成)またはint64_t(-131,071に64を掛けた結果を保持)に変換します。

長い答え:

接尾辞のない整数の10進定数のタイプは、その値によって異なります。これは、その値を表すことができるこのリストの最初のものです:int、long int、longlongint。(接尾辞を追加するか、8進数または16進数の定数を使用すると、リストが変更されます。)これらのタイプはC実装に依存するため、動作はC実装に依存します。

お使いのマシンでは、intは32ビットである可能性があります。したがって、「65535」のタイプはintであり、「64」のタイプも同様です。

式は「65535*65535」で始まります。これは65,535を65,535で乗算します。数学的な結果は4,924,836,225(16進数で0xfffe0001)です。32ビットのsignedintの場合、これは表現可能な値をオーバーフローします。これは、C標準では未定義の動作です。多くの実装で一般的に発生するのは、値が2 31 -1(表現可能な最高値)から-2 31(表現可能な最低値)に「ラップアラウンド」することです。同じ動作の別の見方は、数学的な結果のビット0xfffe0001が、32ビットのsignedintのエンコードとして解釈されることです。2の補数では、0xffffe0001は-131,071です。

次に、式に64を掛けます。-131,071*64はオーバーフローしません。結果は-8,388,544(エンコーディング0xff800040)です。

最後に、結果を使用してuint64_tまたはint64_tオブジェクトを初期化します。この初期化により、宛先タイプに変換されます。

int64_t変換は簡単です。変換への入力は-8,388,544であり、これはint64_tで正確に表現できるため、結果は-8,388,544になります。これは、コンパイラが符号ビットを拡張する(エンコーディング0xffffffffff800040を生成する)だけで実装できる可能性があります。

-8,388,544はuint64_tで表すことができないため、uint64_tの変換は面倒です。1999 C規格、6.3.1.3 2によると、「値は、値が新しいタイプの範囲内になるまで、新しいタイプで表すことができる最大値より1つ多い値を繰り返し加算または減算することによって変換されます。」uint64_tの場合、「新しいタイプで表現できる最大値より1つ多い」は264です。したがって、結果は-8,388,544 + 2 64となり、18,446,744,073,701,163,072になります。これには、エンコーディング0xffffffffff800040もあります。

狭い幅から広い幅に変換する場合、最大値より1つ多く追加するこの操作は、古いタイプの符号ビットを新しいタイプのすべての上位ビットにコピーすることと同じです(符号拡張)。広い幅から狭い幅への変換では、上位ビットを破棄するのと同じです。いずれの場合も、結果は2 nを法とする剰余になります。ここで、nは新しいタイプのビット数です。

于 2012-08-09T12:43:15.510 に答える
2

あなたの例をコンパイルすると、それらの各行に対して整数定数オーバーフロー警告が明らかに表示されます。これは、右側の定数が通常、基本整数で格納されるためです。オーバーフロー状態が発生しないようにするには、これらの値のストレージを変更する必要があります。これを修正するには、代わりに次の手順を実行します。

uint64_t sum_squared_X = (uint64_t)65535*65535*64;
int64_t sum_squared_Y = (uint64_t)65535*65535*64;

詳細はこちら

于 2012-08-09T12:14:38.693 に答える