ここでチェックとチェックされていない点の違いは、実際ILのバグか悪いソースコードです(私は言語の専門家ではないので、C#コンパイラが正しい曖昧なソースコードについてはILを参照してください)。 4.0.30319.1バージョンのC#コンパイラを使ってこのテストコードをコンパイルしました(ただし、2.0の検証でも同じことが起こりました)。私が使用したコマンドラインオプションは/ o +/unsafe/debug:pdbonlyでした。未確認のブロックについては
、我々は、このILコードを持っている:ILで
//000008: unchecked
//000009: {
//000010: Console.WriteLine("{0:x}", (long)(testPtr + offset));
IL_000a: ldstr "{0:x}"
IL_000f: ldloc.0
IL_0010: ldloc.1
IL_0011: add
IL_0012: conv.u8
IL_0013: box [mscorlib]System.Int64
IL_0018: call void [mscorlib]System.Console::WriteLine(string,
object)
はアドオンが2つのオペランド、byte型の1 *とタイプUINT32の他を取得し、11を相殺しました。 CLI仕様によれば、これらは実際にはそれぞれintとint32に標準化されています。 CLI仕様(正確にはパーティションIII)によると、結果はネイティブintになります。したがって、secodnオペランドは、ネイティブint型に昇格させる必要があります。仕様によれば、これは符号拡張を介して達成される。したがって、uint.MaxValue(符号付き表記では0xFFFFFFFFまたは-1)は符号が0xFFFFFFFFFFFFFFFFに拡張されます。次に、2つのオペランドが追加されます(0x0000000008000000L +(-1L)= 0x0000000007FFFFFFL)。 convオペコードは、ネイティブintをint64に変換するための検証目的でのみ必要です。int64は、生成されたコードではnopです。
は今すぐチェックをブロックするために、我々は、このILを持っている:
//000012: checked
//000013: {
//000014: Console.WriteLine("{0:x}", (long)(testPtr + offset));
IL_001d: ldstr "{0:x}"
IL_0022: ldloc.0
IL_0023: ldloc.1
IL_0024: add.ovf.un
IL_0025: conv.ovf.i8.un
IL_0026: box [mscorlib]System.Int64
IL_002b: call void [mscorlib]System.Console::WriteLine(string,
object)
それはアドオンとCONVオペコードを除き、実質的に同一です。オペコードを追加するために、2つの '接尾辞'を追加しました。最初のものは明白な意味を持つ ".ovf"接尾辞です:オーバーフローをチェックしますが、2番目の接尾辞: ".un"も有効にする必要があります。 (すなわち、「add.un」はなく、「add.ovf.un」のみである)。 ".un"には2つの効果があります。最も明白なのは、オペランドが符号なし整数であるかのように、オーバーフローチェックが追加で行われることです。私たちのCSクラスの方法からは、2の補数バイナリエンコーディングのおかげで、符号付き加算と符号なし加算が同じであることを覚えているでしょうから、 ".un"は実際にオーバーフローチェックにのみ影響します。
間違っています。
ILスタックには2つの64ビット数値がないことに注意してください。int32とネイティブint(正規化後)があります。まあ、 ".un"は、int32からネイティブへの変換が上記のようにデフォルトの "conv.i"ではなく "conv.u"のように扱われることを意味します。したがって、uint.MaxValueはゼロで0x00000000FFFFFFFFLに拡張されます。その後、addは0x0000000107FFFFFFLを正しく生成します。コンボオペコードは、符号なしのオペランドを符号付きint64として表現できることを保証します。
あなたの修正プログラムは、64ビットで検索されます。 ILレベルでは、uint32オペランドをネイティブintまたはunsigned native intに明示的に変換することにより、32ビットと64ビットの両方でcheckとuncheckedが同じになります。
あなたのコードの一部を表示できますか? – aL3891
オフセットが符号付きで、ポインタが符号なしですか?負のオフセットはめったに必要ありません。 –
コードの関連する部分は次のようになります。this.currentLocation + = sizeof(byte)、this.currentLocation + = numberOfChildren * sizeof(ushort)、this.currentLocation + = subTree.Lengthなど負のオフセットはありません。 –