25

この質問のトピックは、VS が C# の算術オーバーフローをチェックし、例外をスローする方法です: C# オーバーフローが機能していませんか? オーバーフロー チェックを有効にする方法

コメントの 1 つは奇妙なことを述べており、多くの支持を得ました。ここで私を助けてくれることを願っています:

また、checked キーワードを使用してステートメントまたは一連のステートメントをラップし、算術オーバーフローが明示的にチェックされるようにすることもできます。多くの場合、オーバーフローはかなり合理的な予想であるため、プロジェクト全体のプロパティを設定するのは少し危険です。

ハードウェアについてはよくわかりませんが、オーバーフローがレジスタの動作に関係していることは知っています。オーバーフローは未定義の動作を引き起こすため、可能な限り防止する必要があると常に考えていました。(「通常の」プロジェクトでは、悪意のあるコードを記述していません)

オーバーフローが発生することを期待する理由と、可能性がある場合に常にそれを防止しない理由は何ですか? (対応するコンパイラ オプションを設定することにより)

4

13 に答える 13

36

オーバーフローが必要な主な時間は、ハッシュ コードの計算です。そこでは、結果の実際の数値の大きさはまったく問題ではありません。事実上、たまたま算術演算で操作しているビット パターンにすぎません。

Noda Timeのプロジェクト全体で算術演算がオンになっていることを確認しました- 間違ったデータを返すよりも例外をスローしたいです。オーバーフローが望ましいことはかなりまれだと思います...デフォルトであるという理由だけで、通常はデフォルトを未チェックの算術のままにしておくことを認めます。もちろん、速度のペナルティもあります...

于 2011-02-02T21:24:03.620 に答える
10

オーバーフローは未定義の動作を引き起こすため、可能な限り防止する必要があると常に考えていました。

また、バッファ オーバーフロー (オーバーラン) と数値オーバーフローの違いについて混乱するかもしれません。

バッファ オーバーフローは、アンマネージ配列の末尾を超えてデータが書き込まれる場合に発生します。スタック上の戻りアドレスをユーザーが入力したデータで上書きするなど、未定義の動作を引き起こす可能性があります。マネージ コードでバッファ オーバーフローを実行するのは困難です。

ただし、数値オーバーフローは明確に定義されています。たとえば、8 ビットのレジスタがある場合、2^8 の値 (符号なしの場合は 0 から 255) しか保存できません。したがって、100+200 を加算すると、300 にはなりませんが、300 modulo 256 (44) になります。符号付き型を使用すると、話はもう少し複雑になります。ビット パターンは同様の方法でインクリメントされますが、2 の補数として解釈されるため、2 つの正の数を加算すると負の数になる可能性があります。

于 2011-02-02T21:26:19.947 に答える
9

常に増加するカウンターで計算を行う場合。古典的な例は Environment.TickCount です。

int start = Environment.TickCount;
DoSomething();
int end = Environment.TickCount;
int executionTime = end - start;

それがチェックされた場合、プログラムは、Windows が起動されてから 27 日後に爆弾を投下する可能性があります。DoSomething の実行中に TickCount が int.MaxValue を超えてティックしたとき。PerformanceCounter は別の例です。

これらのタイプの計算は、オーバーフローが存在する場合でも正確な結果を生成します。2 番目の例は、代表的なビット パターンを生成するために行う数学の種類です。実際には、正確な結果には関心がなく、再現可能な結果だけに関心があります。それらの例は、チェックサム、ハッシュ、乱数です。

于 2011-02-02T21:31:27.630 に答える
5

角度

オーバーフローする整数は、角度を測定するためのエレガントなツールです。あなたは0 == 0度、0xFFFFFFFF == 359.999 ....度を持っています。32ビット整数として角度を加算/減算できるため、非常に便利です(350度と20度がオーバーフローして10度に戻ります)。また、32 ビット整数を符号付き (-180 ~ 180 度) および符号なし (0 ~ 360) として扱うこともできます。0xFFFFFFF は -179.999... に相当し、これは 359.999... に相当し、これは同等です。とてもエレガント。

于 2011-02-03T03:03:00.500 に答える
3

可能性があるなら、なぜいつもそれを防ごうとしないのですか?

チェック演算がデフォルトで有効になっていない理由は、チェック演算がチェックされていない演算よりも遅いためです。オーバーフローの発生は通常エラーであるため、パフォーマンスが問題にならない場合は、チェックされた算術演算を有効にするのがおそらく理にかなっています。

于 2011-02-02T21:21:17.790 に答える
3

HashCodes を生成するときは、文字列から言ってください。

于 2011-02-02T21:24:27.817 に答える
3

これはおそらく、技術的な理由と同じくらい歴史と関係があります。整数オーバーフローは、動作に依存するアルゴリズム (特にハッシュ アルゴリズム) によって効果的に使用されることがよくあります。

また、ほとんどの CPU はオーバーフローを許可するように設計されていますが、プロセスでキャリー ビットを設定します。これにより、自然なワード サイズよりも長い加算を簡単に実装できます。このコンテキストでチェック操作を実装するには、キャリー フラグが設定されている場合に例外を発生させるコードを追加する必要があります。それほど大きな負担ではありませんが、コンパイラの作成者は、選択の余地なく人々に押し付けたくなかったのでしょう。

別の方法は、デフォルトでチェックすることですが、チェックされていないオプションを提供します。なぜそうではないのかは、おそらく歴史にまでさかのぼります。

于 2011-02-02T21:27:15.070 に答える
2

デルタで測定されるものでそれを期待するかもしれません。一部のネットワーク機器では、カウンターのサイズを小さく保ち、転送されたバイト数などの値をポーリングできます。値が大きくなりすぎると、オーバーフローしてゼロに戻ります。頻繁に測定している場合 (バイト/分、バイト/時間) にはまだ有用な情報が得られます。カウンターは通常、接続が切断されるとクリアされるため、完全に正確でなくてもかまいません。

Justin が述べたように、バッファ オーバーフローは別のやかんです。これは、配列の末尾を超えてメモリに書き込むべきではない場所です。数値オーバーフローでは、同じ量のメモリが使用されます。バッファ オーバーフローでは、割り当てていないメモリを使用します。一部の言語では、バッファ オーバーフローが自動的に防止されます。

于 2011-02-02T21:30:54.607 に答える
1

プログラムの設計でオーバーフローを利用したプログラマーについての古典的な話が 1 つあります。

メルの物語

于 2011-02-02T21:22:39.493 に答える
1

これは、データを格納する変数のメモリの制限にすぎないため、レジスタの動作とはあまり関係ありません。(レジスターをオーバーフローさせずに、メモリー内の変数をオーバーフローさせることができます。)

しかし、あなたの質問に答えるために、最も単純なタイプのチェックサムを考えてみてください。これは、チェックされるすべてのデータの単純な合計です。チェックサムがオーバーフローしても問題はなく、オーバーフローしなかった部分は意味を持ちます。

その他の理由には、重要でない変数がオーバーフローした可能性がある場合でも、プログラムを実行し続けたいという理由が含まれる場合があります。

于 2011-02-02T21:26:01.723 に答える
0

すべての整数演算(少なくとも加算と減算および乗算)は正確です。注意する必要があるのは、結果のビットの解釈にすぎません。2の補数システムでは、ビット数に対して2を法として正しい結果が得られます。符号付きと符号なしの唯一の違いは、符号付き数値の場合、最上位ビットが符号ビットとして扱われることです。何が適切かを判断するのはプログラマー次第です。明らかに、一部の計算では、オーバーフローについて知り、オーバーフローが検出された場合は適切なアクションを実行する必要があります。個人的には、オーバーフロー検出は必要ありませんでした。私はそれに依存する線形合同乱数ジェネレーターを使用します。つまり、64 * 64ビットの符号なし整数乗算です。最下位の64ビットのみを考慮し、切り捨てのためにモジュロ演算を無料で取得します。

于 2011-02-03T00:14:20.843 に答える
0

整数オーバーフローは次のようになります。

8 ビット整数 1111 1111 があり、これに 1 を追加します。0000 0000 の場合、先頭の 1 は 9 番目になるため切り捨てられます。

符号付き整数があるとします。先頭のビットはそれが負であることを意味します。これで 0111 1111 になりました。これに 1 を加えると 1000 0000 になり、-128 になります。この場合、127 に 1 を加えるとマイナスに切り替わります。

オーバーフローは適切に決定された方法で動作すると確信していますが、アンダーフローについてはわかりません。

于 2011-02-02T22:08:06.683 に答える
0

私がイメージできるもう 1 つの可能性のある状況は、乱数生成アルゴリズムです。必要なのは乱数だけなので、その場合のオーバーフローは考慮しません。

于 2011-02-02T21:25:59.273 に答える