21

CおよびC++が、オーバーフローチェックが提供された基本的な整数演算のそれぞれを実行するための実装提供の一連の演算を提供しないのはなぜですか(例:)bool safeAdd(int *out, int a, int b)

私が理解しているように、ほとんどの命令セットには、操作がオーバーフローしたかどうか(x86オーバーフローやキャリーフラグなど)を判断する方法があり、符号付き整数の場合に定義も発生します。

そのため、コンパイラーは、CおよびC ++でコーディングできるものよりもはるかに優れた仕事をして、より単純で高速な操作を作成できるべきではありませんか?

4

6 に答える 6

10

C と C++ は、「必要のないものにはお金を払わない」という中心的な信条に従います。したがって、デフォルトの算術演算は、基盤となるアーキテクチャの算術演算用の単一の命令から逸脱することはありません。

2 つの整数を加算してオーバーフローを検出するための標準ライブラリ関数がない理由については、私にはわかりません。まず第一に、言語は符号付き整数オーバーフローを未定義の動作として定義しているようです:

C プログラミング言語では、符号付き整数のオーバーフローによって未定義の動作が発生します。

符号付き整数 (1 の補数、2 の補数など) を実装するには複数の方法があり、C が作成されたとき、これらのアーキテクチャはすべて普及していたことを考慮すると、これが未定義である理由は理解できます。基礎となるプラットフォームに関する多くの情報がなければ、「安全な*」純粋な C関数を実装することは困難です。CPUごとに知ることで実行できます。

それでも、それを不可能にするわけではありません。より安全なオーバーフロー ヘルパーを備えた C または C++ 標準化団体への提案を誰かが見つけて、それらが拒否された理由を確認できれば、私は間違いなく興味があります。

いずれにせよ、実際には算術オーバーフローを検出する方法や役立つライブラリが多数あります。

于 2012-08-22T11:11:53.610 に答える
6

という質問が定期的に出てきます。

まず、C は移植可能効率的であると定義されていることを思い出してください。そのため、多くのハードウェアでサポートされている操作のみを提供するように設計されています (おそらく x86 が登場する前)。

第二に、多くのコンパイラがそのような操作用の組み込みを提供 (または提供する予定) しているため、ユーザーはこれらの組み込みを内部で使用するクラス型を使用できます。ビルトインの実装の品質は、その意味を認識しているコンパイラーが、それらが役に立たないことが証明されている場合にチェックアウトを最適化する可能性があるという事実ほど重要ではありません (ただし、重要です)。

最後に、実際にプログラムをチェックする方法は他にもあります。たとえば、静的解析または特別なコンパイル モードと単体テストにより、これらの欠陥が早期に検出され、リリース ビルドにオーバーフロー チェックを埋め込む必要が (多かれ少なかれ完全に) 回避される場合があります。

于 2012-08-22T11:19:10.543 に答える
6

需要がないからでしょう。算術オーバーフローは未定義の動作であり、明示的に実装がそのようなチェックを実行できるようにするためのものです。コンパイラーのベンダーが、それを行うことでより多くのコンパイラーを販売できると考えた場合、そうするでしょう。

実際には、コンパイラーがプログラマーよりも効果的にそれらを行うことは非常に困難です。すべての数値入力の範囲を検証し、後の操作がオーバーフローしないことを証明できる範囲にするのは、ほぼ標準的な手順です。すべての優れたプログラマーは、これを習慣として行っています。したがって、これはif 、入力直後に 1 つのクイックが実行され、それ以上のチェックが行われないことを意味します。

それでも、プログラマーは間違いを犯すことが知られており、後で計算を変更するときに検証を修正するのを忘れがちです。コンパイラにそのような機能があればいいのにと思います。しかし、どうやらそれはコンパイラの販売には役立たないか、少なくともベンダーはそうはならないと信じているため、私たちはそれを理解していません。

于 2012-08-22T11:04:43.537 に答える
5

必要になることはめったにないからです。実際に整数オーバーフローを検出する必要があるのはいつですか? 範囲をチェックする必要があるほぼすべての状況で、通常、実際の範囲を定義するのはユーザーです。これは、この範囲がアプリケーションとアルゴリズムに完全に依存するためです。

int結果が特定のアルゴリズムの許可されたドメイン内にあるかどうか、またはインデックスが配列の境界内にあるかどうかを知る代わりに、結果が範囲を超えているかどうかを本当に知る必要があるのはいつですか? 変数にセマンティックを与えるのはあなたです。言語仕様は型の全体的な範囲のみを提供します。範囲がニーズに合わない型を選択した場合、それはあなたの責任です。

整数オーバーフローは UB です。ほとんど気にしないからです。操作中にオーバーフローが発生した場合は、unsigned char1,000 万の数値を累積するために間違った型を選択した可能性があります。しかし、実行時のオーバーフローについて知っていても、設計が壊れているため役に立ちません。

于 2012-08-22T12:15:22.917 に答える
4

より良い質問は、整数オーバーフローが未定義の動作である理由です。実際には、すべてのCPUの99.9%が2の補数とキャリー/オーバーフロービットを使用します。したがって、現実の世界では、アセンブラ/オペコードレベルでは、整数のオーバーフローは常に明確に定義されています。実際、多くのアセンブラー、またはハードウェア関連のCは、明確に定義された整数のオーバーフロー(特にタイマーハードウェアのドライバー)に大きく依存しています。

標準化前の元のC言語は、おそらくこのようなことを詳細に考慮していませんでした。しかし、CがANSIとISOによって標準化されたとき、それらは特定の標準化規則に従わなければなりませんでした。ISO規格は、特定のテクノロジーに偏って、それによって特定の企業に競争上の優位性を与えることは許可されていません。

そのため、一部のCPUは、補数、「符号と大きさ」、「実装で定義された方法」などのあいまいなものを実装する可能性があることを考慮しなければなりませんでした。彼らは、符号付きゼロ、パディングビット、およびその他のあいまいな符号付き整数メカニズムを許可する必要がありました。

そのため、符号付き数値の振る舞いは素晴らしく曖昧になりました。符号付き整数は2の補数、1の補数、または場合によっては他の実装定義の狂気で表現される可能性があるため、Cの符号付き整数がオーバーフローしたときに何が起こるかはわかりません。したがって、整数のオーバーフローは未定義の動作です。

この問題の正しい解決策は、いくつかの安全な範囲チェックを発明することではなく、C言語のすべての符号付き整数が2の補数形式であると述べることです。その場合、unsigned charは常に0から127になり、オーバーフローは-128になり、すべてが明確に定義されます。しかし、人工的な標準官僚機構は、標準が正気になるのを防ぎます。

C規格にはこのような問題がたくさんあります。アラインメント/パディング、エンディアンなど。

于 2012-08-22T11:30:46.650 に答える
4

なんで?なぜなら、C++ がそこから始まったとき、それらは C になかったからです。それ以来、誰もそのような関数を提案しておらず、提供するのに十分有用であるとコンパイラ メーカーや委員会のメンバーを説得することに成功したからです。

コンパイラはそのような種類の組み込み関数を 提供しているため、それらに反対しているわけではないことに注意してください。

Fixed-Point ArithmeticUnbounded-Precision Integer Typesなどを標準化する命題があることにも注意してください。

ということは、単に興味が足りないだけかもしれません。

于 2012-08-22T11:11:29.893 に答える