33

たぶん私は基礎を学んでいますが、まだ学校でこの C# のことを勉強しています。32ビットの最大値の整数に1を追加すると、結果が負になることを理解しています。C# には、オーバーフローを処理するためのチェック済みキーワードとチェックなしキーワードが用意されていると読みました。チェックされたキーワードは何か、私は便利だと思いましたが、チェックされていないキーワードはどうですか? チェックされていない -keyworded ブロックの有用な用途があまり見つかりません。ありますか?次の 2 つのアプローチはどのように異なりますか?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Practice_6
{
    class Program
    {
        static void Main(string[] args)
        {
            int value = Int32.MaxValue;
            value++;
            //Approach 1 to make a decision
            if (value > Int32.MaxValue) {
                //Do something
            }
            value = Int32.MaxValue;
            //Approach 2 to make a decision
            unchecked {
                value++;
                //Do something
            }
            //What's the difference between these two approaches to handle overflow?
    }
}
4

5 に答える 5

50

更新: この質問は、2015 年 4 月の私のブログの主題でした。興味深い質問をありがとう!


最初の質問は次のとおりです。

checkedキーワードは便利ですが、キーワードはどうでしょuncheckedうか。本当に使い道が思いつかない。ありますか?

C# の設計チームは、言語に関係のない機能を追加する習慣はありません。(世界で最も役に立たない演算子である単項プラス演算子は例外です。)

unchecked キーワードには、主に 2 つの使用例があります。

まず、定数整数演算はデフォルトで常にチェックされます。これはイライラすることがあります。たとえば、いくつかの相互運用コードがあり、HRESULT E_FAIL の定数を作成したいとします。

const int E_FAIL = 0x80004005;

その数値は大きすぎて に収まらないため、これはエラーですint。しかし、 を使いたくないかもしれませんuint。あなたはよく考えるかもしれません

const int E_FAIL = (int)0x80004005;

しかし、変換を含む定数演算はデフォルトで常にチェックされるため、これも違法です。

あなたがしなければならないことは、チェックされた定数演算をオフにすることです

const int E_FAIL = unchecked((int)0x80004005);

第 2 に、C# の非定数整数演算の既定の演算はチェックされていません。これは、C# の方が高速であり、他の多くの同様の言語が行っていることであるためです。ただし、C# では、コンパイラ フラグを使用して、定数でない整数演算のデフォルトをチェック演算に変更できます。そうした後、一時的に再びオフにする必要がある場合は、uncheckedブロックまたは式の構文を使用する必要があります。

3 番目の使用例は、チェックされていないブロックを自己文書化コードの形式として使用して、「ここで実行している操作がオーバーフローする可能性があることを認識しており、それで問題ない」と言うことです。たとえば、私はよく次のように書きます。

int GetHashCode()
{
    unchecked 
    {
        int fooCode = this.foo == null ? 0 : this.foo.GetHashCode();
        int barCode = this.bar == null ? 0 : this.bar.GetHashCode();
        return fooCode + 17 * barCode;
    }
}

「未チェック」は、ハッシュコードの乗算と加算がオーバーフローする可能性があることを完全に予想していること、およびこれは問題ないことを読者に強調しています。

2 番目の質問は次のとおりです。

オーバーフローを処理するこれら 2 つのアプローチの違いは何ですか?

良い質問。

あなたのチェックされたコンテキストであなたが意味する場合:私は算術が常に範囲内にあることを期待しています。そうでない場合、私のプログラムには深刻なバグがあり、世界にさらに害を及ぼす前に終了する必要があります。オーバーフローがないため、オーバーフローチェックをまったく行うべきではありません。例外が発生すると、プログラムを終了する必要があります。チェックされたコンテキストは、コードの正確性を検証するためにランタイムを機能させるだけです。

チェックされたコンテキストで、算術が範囲内にある必要があるが、信頼できないソースからこのデータを取得し、範囲チェックを行うのが面倒な場合は、例外をキャッチする必要があります。 ただし、実行時に問題を認識してオーバーフロー例外をスローするよりも、範囲チェックを実行して、データが範囲外の場合により意味のあるエラーを発生させる方が適切です。例外をキャッチするのではなく、範囲チェックを強くお勧めします。怠惰にならないでください。

于 2014-09-18T16:00:43.947 に答える
5

checkedとのパフォーマンスへの影響についてはよくわかりませんunchecked。理論的にuncheckedは、パフォーマンスが向上するはずであり、これがデフォルトのコンテキストです。ある種の特別なアルゴリズム/ビジネスロジックなどのために整数型の境界をぶらぶらしていない限り、使用checkedが必要/有用/読み取り可能になることはめったにありません。

私が言ったようにunchecked、デフォルトのコンテキストであるのに、なぜuncheckedキーワードが必要なのですか? コンテキストの使用頻度が高い場合は、コンテキストのタイプを明示することもできますchecked。もう 1 つは、uncheckedコンテキスト内checkedでコンテキストを使用することです。

checked {
    int a = 5 + 1231;

    unchecked {
        a += 221;
    }
}

あなたの質問は、デフォルトのコンテキストがチェックされていない理由かもしれません。マイクロソフトによる設計上の選択だと思います。

それらの違いは、checked算術演算ごとにオーバーフローがあるかどうかをコンテキストがチェックし、オーバーフローがある場合は例外を発生させることです。

于 2014-09-11T03:40:09.187 に答える
2

MSDN から unchecked を使用する理由は次のとおりです。

オーバーフローのチェックには時間がかかるため、オーバーフローの危険がない状況で未チェックのコードを使用すると、パフォーマンスが向上する場合があります。ただし、オーバーフローの可能性がある場合は、チェック済み環境を使用する必要があります。

于 2014-09-11T03:40:21.233 に答える
0

コードを次のように変更します。

  int value = int.MaxValue;
  unchecked
  {
    value++;
  }
  Console.WriteLine(value);
  value = int.MaxValue;
  checked
  {
    value++; // this will raise OverflowException
  }

違いがわかります。

于 2014-09-11T03:40:22.587 に答える