2013-01-07 5 views
12

int32を64ビットnative intに追加する場合、CLRは32ビット整数の符号拡張またはゼロ拡張を行いますか?そして最も重要なのは、どの情報に基づいてこの選択をするのか?64ビットのネイティブintにint32を追加した結果は?


私は.NETコンパイラを書いていますし、徹底的にECMA仕様を読んだが、答えを見つけることができませんでした。 int32int64、及びnative int

はCLIは、その評価スタック上に格納された値に、その操作にこれらのタイプのサブセットのみをサポートします。
からECMA 335、セクションIは12.1:のための1:サポートされているデータ型

評価スタック上の値はその符号の有無についての情報、オペランドの符号の有無は、2つのバリエーションを持っている問題ではそのための手順を持っていないので、 1つは符号なし整数です。オーバーフローをチェックしない命令は、オペランドが同じサイズである限り、オペランドの符号性を気にする必要はないので、単一のバリアントしか持たない。ただし、オペランドが常に同じサイズではない...

ECMA 335、セクションIII 1.5:オペランドタイプテーブル状態int32native intが減算、添加することができる、乗算と分割。結果は再びnative intです。 64ビットシステムでは、native 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,int64およびnative int(およびここでは関係のないもの)のみが分かります。


それは内部的にネイティブint型として表現されているので、私はまた、追加のこの種を使用することになり、そのIntPtrUIntPtr算術を想像。ただし、ILSpyは、IntPtrInt32をC#で追加すると、IntPtrクラスのオーバーロードされた+演算子が呼び出され、符号付きInt32引数のみを受け付けることが示されています。

CILで直接実行すると(add命令を使用)、整数が符号付きとして解釈されます。 Monoでも実装されているはずですが、私の知見を裏付ける参考文献は見つかりませんでした。

+0

昇格された値の記号は捕捉されません。可能な解決策については、この情報を参照してください(Macの場合ですが、この場合は問題ありません):https://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/64bitPorting/MakingCode64-BitClean/MakingCode64- BitClean.html – K3N

答えて

5

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

ただし、異なるビットサイズの2つの値を加算すると、符号つきとなります。たとえば、32ビットの-10から64ビット10を加算すると、符号なしの場合は4294967296(0x100000000)、符号付きの場合は0になります。

CIL add命令は、ネイティブ整数32ビット整数を加えることができます。ネイティブ整数は、64ビット(64ビットシステム)である可能性があります。 テストでは、addは32ビット整数を符号付き整数として扱い、符号拡張しています。This is not always correctであり、a bugと考えることができる。マイクロソフトは現在、それを修正するつもりはありません。

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

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

2

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

iffyセマンティクスと将来のジッタの変化が想定を破る可能性が非常に高いことを考えれば、あなた自身の言語でこれも拒否することを強く推奨します。これはあまり有用ではないだけでなく、(long)にキャストする単純な回避策と(IntPtr)に戻る結果は明確なセマンティクスを持っています。あなた自身のコードジェネレータで予測可能な振る舞いを得る方法は、それ自身です。

+0

私はポストにいくつかの情報を追加しました。C#は 'Int32'に' IntPtr'を追加するときにオーバーロードされた加算演算子を使います。 CILでは、 'add'命令は' Int32'を符号付きとして解釈しているようです。しかし、私は理由を知らない。 – Virtlink

関連する問題