49

いくつかの最新のプログラミング言語 (C++、Java、および C# を含む) では、この言語では、実行時に整数オーバーフローが発生しても、エラー状態が発生することはありません。

たとえば、オーバーフロー/アンダーフローの可能性を考慮していない、この (考案された) C# メソッドについて考えてみましょう。(簡潔にするために、このメソッドは、指定されたリストが null 参照の場合も処理しません。)

//Returns the sum of the values in the specified list.
private static int sumList(List<int> list)
{
    int sum = 0;
    foreach (int listItem in list)
    {
        sum += listItem;
    }
    return sum;
}

このメソッドが次のように呼び出された場合:

List<int> list = new List<int>();
list.Add(2000000000);
list.Add(2000000000);
int sum = sumList(list);

sumList()メソッドでオーバーフローが発生します( intC# の型は 32 ビット符号付き整数であり、リスト内の値の合計が最大 32 ビット符号付き整数の値を超えるため)。sum 変数の値は -294967296 になります (4000000000 の値ではありません)。これはおそらく、sumList メソッドの (架空の) 開発者が意図したものではありません。

明らかに、開発者が整数オーバーフローの可能性を回避するために使用できるさまざまな手法があります。たとえば、Java の のような型を使用しBigIntegerたり、 C# でcheckedキーワードと/checkedコンパイラ スイッチを使用したりします。

しかし、私が興味を持っているのは、これらの言語が、たとえば、実行時に操作が実行されたときに例外を発生させて、オーバーフロー。このような動作は、オーバーフローが発生する可能性のある算術演算を実行するコードを記述する際に、開発者がオーバーフローの可能性を考慮することを怠った場合に、バグを回避するのに役立つようです。(これらの言語には、開発者がその動作を明示的に意図している場合に、例外が発生することなく整数オーバーフローの発生が許可されるブロックを指定できる「unchecked」キーワードのようなものが含まれていた可能性があります。C# には実際に this . )

答えは単純にパフォーマンスに帰着しますか?言語設計者は、該当するすべての算術演算で、オーバーフローが発生したかどうかを確認するためにランタイムが余分な作業を行う必要がある「遅い」算術整数演算をそれぞれの言語にデフォルトで設定することを望んでいませんでした。操作 - このパフォーマンスの考慮事項は、不注意なオーバーフローが発生した場合の「サイレント」障害を回避する価値を上回りましたか?

パフォーマンスの考慮事項以外に、この言語設計の決定にも他の理由はありますか?

4

9 に答える 9

43

C# では、パフォーマンスの問題でした。具体的には、すぐに使えるベンチマークです。

C# が新しく登場したとき、Microsoft は多くの C++ 開発者が C# に切り替えることを望んでいました。彼らは、多くの C++ 関係者が C++ を高速であると考えていることを知っていました。特に、自動メモリ管理などに時間を「浪費」する言語よりも高速です。

潜在的な採用者と雑誌のレビュアーの両方が、新しい C# のコピーを入手してインストールし、現実の世界では誰も作成しないであろう簡単なアプリを構築し、それをタイトなループで実行して、所要時間を測定する可能性があります。その後、彼らは会社のために決定を下したり、その結果に基づいて記事を公開したりします.

彼らのテストで C# がネイティブにコンパイルされた C++ よりも遅いことが示されたという事実は、人々がすぐに C# を離れてしまうようなものです。C# アプリがオーバーフロー/アンダーフローを自動的にキャッチしようとしているという事実は、彼らが見逃す可能性のあるものです。したがって、デフォルトではオフになっています。

99% の時間で /checked をオンにしたいのは明らかだと思います。残念な妥協です。

于 2008-09-20T17:15:15.730 に答える
26

パフォーマンスはかなりの理由だと思います。整数をインクリメントする典型的なプログラムのすべての命令を考慮し、1 を加算する単純な操作の代わりに、1 を加算すると型がオーバーフローするかどうかを毎回チェックする必要がある場合、余分なサイクルのコストはかなり深刻になります。

于 2008-09-19T16:55:49.297 に答える
16

整数オーバーフローは常に望ましくない動作であるという前提で作業します。

整数オーバーフローが望ましい動作である場合があります。私が見た 1 つの例は、固定小数点数としての絶対見出し値の表現です。unsigned int を指定すると、0 は 0 または 360 度であり、最大 32 ビットの符号なし整数 (0xffffffff) は 360 度のすぐ下の最大値です。

int main()
{
    uint32_t shipsHeadingInDegrees= 0;

    // Rotate by a bunch of degrees
    shipsHeadingInDegrees += 0x80000000; // 180 degrees
    shipsHeadingInDegrees += 0x80000000; // another 180 degrees, overflows 
    shipsHeadingInDegrees += 0x80000000; // another 180 degrees

    // Ships heading now will be 180 degrees
    cout << "Ships Heading Is" << (double(shipsHeadingInDegrees) / double(0xffffffff)) * 360.0 << std::endl;

}

この例のように、オーバーフローが許容される状況はおそらく他にもあります。

于 2008-09-19T17:01:33.197 に答える
8

C/C++ は、トラップ動作を強制することはありません。明らかな 0 による除算でさえ、C++ では定義されていない動作であり、特定の種類のトラップではありません。

シグナルをカウントしない限り、C 言語にはトラップの概念がありません。

C++ には、要求しない限り、C に存在しないオーバーヘッドを導入しないという設計原則があります。したがって、Stroustrup は、明示的なチェックが必要な方法で整数が動作することを強制したくありませんでした。

一部の初期のコンパイラ、および制限付きハードウェア向けの軽量実装では、例外がまったくサポートされず、多くの場合、例外はコンパイラ オプションで無効にできます。言語組み込みの例外を強制することは問題があります。

C++ が整数をチェックしていたとしても、初期のプログラマの 99% は、パフォーマンス向上のためにオフにしていたでしょう...

于 2008-09-19T18:12:24.290 に答える
7

オーバーフローのチェックには時間がかかるためです。通常は単一のアセンブリ命令に変換される各プリミティブ数学演算には、オーバーフローのチェックを含める必要があり、その結果、複数のアセンブリ命令が生成され、プログラムが数倍遅くなる可能性があります。

于 2008-09-19T16:57:42.007 に答える
6

おそらく 99% のパフォーマンスです。x86 では、すべての操作でオーバーフロー フラグをチェックする必要があり、パフォーマンスが大幅に低下します。

残りの 1% は、派手なビット操作を行ったり、符号付き演算と符号なし演算を混在させるのが「不正確」で、オーバーフロー セマンティクスが必要な場合をカバーします。

于 2008-09-19T16:56:57.983 に答える
4

後方互換性は大きなものです。C では、データ型のサイズに十分注意を払い、オーバー/アンダーフローが発生した場合にそれが必要であると想定されていました。その後、C++、C#、および Java では、「組み込み」データ型の動作はほとんど変わりませんでした。

于 2008-09-19T16:59:59.893 に答える
-4

実行時にデフォルトでエラーが発生しない理由についての私の理解は、ACID のような動作を備えたプログラミング言語を作成したいという伝統に帰着します。具体的には、コーディングして実行する (またはコーディングしない) ことはすべて実行する (または実行しない) という信条です。エラーハンドラをコーディングしなかった場合、マシンは、エラーハンドラがないという理由で、あなたが指示したばかげた、クラッシュしやすいことを本当に実行したいと「想定」します。

(ACID リファレンス: http://en.wikipedia.org/wiki/ACID )

于 2008-09-19T16:59:17.447 に答える