web-dev-qa-db-ja.com

未チェック-C#のキーワード

たぶん私は基礎にいるかもしれませんが、私はまだこのC#のことを学校で勉強しています。最大値の整数(1は32ビット)に1を追加すると、結果が負になることを理解しています。 C#では、オーバーフローを処理するためのチェックされたキーワードとチェックされていないキーワードが提供されていることを読みました。チェックされたキーワードは便利ですが、チェックされていないキーワードはどうですか?チェックされていないキーワード付きブロックの実用的な使い方はあまり見つかりません。何かありますか?次の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?
    }
}
30
Jere_Sumell

更新:この質問は 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#では、コンパイラフラグを使用して、非定数整数演算のデフォルトのチェック演算に変更できます。これを行った後、一時的にオフに戻す必要がある場合は、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つのアプローチの違いは何ですか?

良い質問。

あなたのチェックされたコンテキストであなたが意味するならば:私は算術が常に境界内にあると期待します;そうでない場合、私のプログラムには重大なバグがあり、世界に害を与える前に終了する必要がありますオーバーフローがないため、オーバーフローチェックを実行しないでください。例外が発生するとプログラムが終了します。チェックされたコンテキストは、ランタイムがコードの正当性を検証するために機能するようにするだけです。

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

40
Eric Lippert

checkeduncheckedのパフォーマンスへの影響についてはよくわかりません。理論的には、uncheckedの方がパフォーマンスが高く、デフォルトのコンテキストです。ある種の特別なアルゴリズム/ビジネスロジックなどのために整数型の境界を回避しない限り、checkedを使用する必要はほとんどありません。

先ほど言ったように、uncheckedがデフォルトのコンテキストですが、なぜuncheckedキーワードが必要なのですか? 1つのことは、checkedコンテキストの使用率が高いコンテキストのタイプについて明示することです。もう1つは、uncheckedコンテキスト内でcheckedコンテキストを使用することです。

checked {
    int a = 5 + 1231;

    unchecked {
        a += 221;
    }
}

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

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

5
mostruash

適切に作成されたコードは、プロジェクトがデフォルトでチェックされているか、チェックされていない状態でコンパイルされているかに依存するとは考えられません。予期しないラッピング演算動作がセキュリティまたはシステムの安定性にリスクをもたらす可能性があるコードは、checkedコンテキストで実行する必要があります。算術動作のラップに依存するコードは、uncheckedコンテキストで実行する必要があります。算術オーバーフローが発生することは想定されていないが、発生した場合の影響が限定される汎用コードは、プロジェクトレベルの設定を使用してコンパイルする必要があります。実行速度とタイムリーなエラートラップのトレードオフとして、プロジェクトレベルの設定をオンまたはオフに設定できます。

予期しないオーバーフローが発生していない場合、コードはチェックされていないモードでより速く実行されます。ただし、一部の計算で偽の値が生成され、その理由が明確でない場合は、オーバーフローチェックを有効にして再コンパイルすると役立つことがあります。コードの実行が遅くなりますが、最初の誤った計算でトラップされます。ただし、そのような目的でプロジェクトをチェックモードに切り替えることは、ラップ動作に依存するプロジェクトの部分が明示的なuncheckedコンテキストで実行される場合にのみ可能です。そうしないと、プロジェクトレベルのモードを切り替えると、プログラムが完全に壊れてしまいます。

4
supercat

MSDNから、チェックされていないものを使用する理由は次のようになります

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

2
Mike Beeler

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

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

違いがわかります。

0
Setyo N