13

int3264ビットにを追加する場合native int、CLRは32ビット整数を符号拡張しますか、それともゼロ拡張しますか?そして最も重要なのは、どのような情報に基づいてこの選択を行うのかということです。


.NETコンパイラを作成していて、ECMA仕様をよく読んでいますが、答えが見つかりませんでした。

int32CLIは、評価スタックに格納されている値、、、int64およびの操作で、これらのタイプのサブセットのみをサポートしますnative int
--ECMA 335、セクションI 12.1:サポートされているデータ型

評価スタックの値には符号付きの情報がないため、オペランドの符号が重要な命令には、符号付き整数用と符号なし整数用の2つのバリアントがあります。、および命令(オーバーフローをチェックしない命令)は、オペランドが同じサイズである限り、オペランドの符号を気にする必要はありません。したがって、バリアントは1つだけですadd。ただし、オペランドは常に同じサイズであるとは限りません。submul

ECMA 335、セクションIII 1.5:オペランドタイプの表には、anint32とanative intを加算、減算、乗算、および除算できると記載されています。結果は再びnative intです。64ビットシステムでは、anative intは64ビット幅です。

ldc.i4.0            // Load int32 0
conv.i              // Convert to (64-bit) native int
ldc.i4.m1           // Load int32 -1
add                 // Add native int 0 and int32 0xFFFFFFFF together

では、ここでの結果はどうなるでしょうか?仕様によれば、ランタイムはスタック上の値の正確な型や符号を追跡する必要がないことに注意してください。ランタイムは、、int32およびint64native intおよびここでは関係のない他のいくつか)のみを認識します。


算術演算は、内部的にネイティブintとして表されるため、この種の加算も使用するIntPtrと思います。UIntPtrただし、ILSpyは、C#にanIntPtrとaを追加するとInt32、クラスでオーバーロードされた+演算子が呼び出され、符号付き引数IntPtrのみを受け入れることを示しています。Int32

(命令を使用して)CILで直接add実行することは、整数が署名されていると解釈されることも示します。これもMonoで実装されているはずですが、調査結果を裏付けるための参照が見つかりませんでした。

4

2 に答える 2

5

同じビットサイズの2つの値を加算する場合、符号は重要ではありません。たとえば、32ビット-10(0xfffffff6)を32ビット10( )に追加すると、正しく0が生成されます。そのため、CIL(共通命令言語)に0x0000000aは1つの命令しかありません。add

ただし、ビットサイズが異なる2つの値を加算する場合は、符号重要になります。たとえば、32ビット-10を64ビット10に追加する0x100000000と、署名なしで実行された場合は4294967296()になり、署名された場合は0になります。

CIL命令では、ネイティブ整数32ビット整数addを追加できます。ネイティブ整数は64ビット(64ビットシステムの場合)です。テストにより、は32ビット整数を符号付き整数として扱い、それを符号拡張することが明らかになりました。これは常に正しいとは限らず、バグと見なされる場合があります。Microsoftは現在それを修正するつもりはありません。add

add.ovfオーバーフローチェックは、オペランドが符号なしまたは符号付きとして扱われるかどうかに依存するため、 :(符号付きadd.ovf)とadd.ovf.un(符号なし)の2つのバリエーションがあります。ただし、これらのバリアントは、32ビット整数をネイティブ整数に追加するときに、小さい方のオペランドを正しく符号拡張してゼロ拡張します。

したがって、ネイティブ整数と符号なし32ビット整数を追加すると、C#のオーバーフローチェック設定に応じて異なる結果が得られる可能性があります。どうやら私がこれを理解できなかったという事実は、CIL言語設計のバグまたは見落としの結果です。

于 2013-03-04T14:07:40.303 に答える
2

あなたはここで未知の領域にいます、私は実際にこれを許可する.NET言語を知りません。彼らの構文チェッカーは、これを行おうとするコードを拒否します。2つのネイティブintを追加しても拒否されます。最終的には、そのためのマシンコードを生成するのはジッター次第です。何が起こるか知りたい場合は、実験してください。少なくともx86およびx64ジッターをテストしてください。

不安定なセマンティクスと、将来のジッターの変更が想定を破る可能性が非常に高いことを考えると、これも自国語で拒否することを強くお勧めします。これはあまり有用ではなく、(long)にキャストし、結果を(IntPtr)に戻す単純な回避策には、明確に定義されたセマンティクスがあります。これ自体が、独自のコードジェネレーターで予測可能な動作を取得する方法です。

于 2013-01-07T08:28:58.083 に答える