ILAsmの配列
ILAsmの配列がよく理解できませんでした
そこでExpert .NET 2.0 IL Assemblerの内容を適当に訳してまとめした
種類
CLRには2種類の配列があります
vectorとarrayです
1次元配列です。下限値が0に決まっています
- array
多次元配列です。1次元以上の配列を定義できます。下限値には0以外も指定できます
arrayとvectorは別なものとして扱われます
例えば、2次元のarray(実例: int32[..., ...])とvectorのvector(実例: int32)は全く別なものです
int32[..., ...] は1度のインストラクションコールで生成されます
int32は2回のnewarrインストラクションコールで生成されます
ILAsm表記法
vector
[ ]
array
[ [, ] ] ::= [ ] ... [ ]
実例
//vector int32[] //array int32[..., ...] int32[2...5] int32[0..., 0...]
上限値、下限値とも指定しないときは"..."は省略可能です
そのため2次元以上の配列で int32[..., ...] と int32[,] は同じ意味のarrayになります
しかし1次元配列では、"..."は省略時の意味が分かれます
int32[] はvectorを表します
int32[...] はarrayを表します
もし下限値が指定されなかったときは、0だと仮定されます(?:要確認)
また、2次元以上のarrayで2次元目以上の範囲が指定されたときは、
それ以下の次元の範囲も指定します
例えば5次元のarrayで、3次元目の範囲を指定したら、
1次元目、2次元目の範囲も指定します
実例
int32 [ 0...3 , 0...3 , 0...3 , ... , ... ] // OK int32 [ ... , ... , 0...3 , ... , ... ] // NG、1番目、2番目の範囲が未指定 int32 [ ... , 0...3 , 0...3 , ... , ... ] // NG、1番目の範囲が未指定 int32 [ 0...3 , ... , 0...3 , ... , ... ] // NG、2番目の範囲が未指定
インスタンス化
vector、arrayとも[mscorlib]System.Arrayクラスから派生されています
vector、arrayともオブジェクト参照なので、使うときにはインスタンス化します
vectorのインスタンス化は、newarrインストラクションを使います
arrayインスタンス化は、arrayのコンストラクタを使います
インスタンス化をするときは、そのサイズを指定します
そのため配列のサイズは、配列の型の属性ではなく、配列のインスタンスの属性になります
arrayのインストラクション
ILインストラクションセットにはvectorを扱うものはありますが、arrayを扱うものはありません
arrayやarrayの要素を扱うために、[mscorlib]System.Arrayのメソッドを呼ぶ必要があります
そのメソッドは、Get、Set、Addressです
Getメソッドはインデックスを表すN個の引数をとり、そのインデックスが指す値を返します
Addressメソッドも同様に引数をとり、インデックスが指す要素のマネージドポインタを返します
Setメソッドはインデックスを表すN個の引数と、インデックスが指す要素へ代入する値をとり、voidを返します
array生成
arrayコンストラクタは定義されていない下限値と大きさ(上限値)の数だけパラメータをとります
そのためnewobjインストラクションをコールする前に
同じ数の整数値をスタックに積んでおきます
要素アドレス読み込み
要素読み込み
ldelem.i4
int32型の要素をvectorから読み込みます
要素格納
stelem.i4
int32型の要素をvectorに格納します
サンプルプログラム
// コンパイル方法: // ファイル名: tmp.il で保存して、SDK コマンド プロンプトから // > ilasm tmp.il .assembly extern mscorlib {.ver 2:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89)} .assembly tmp{ } .field static int32 a .field static int32 b .method static public void Main() { .entrypoint ldc.i4.s 9 // vectorの要素数を積む newarr int32 // vectorを生成 stsfld int32 a // 変数aに格納 ldsfld int32 a // 変数aを読み込み ldc.i4.0 // インデックスを積む ldc.i4.7 // 値を積む stelem.any int32 // 要素に格納 ldsfld int32 a // 変数aを読み込み ldc.i4.0 // インデックスを積む ldelem.any int32 // 要素を読み込む call void [mscorlib]System.Console::WriteLine(int32) // -> 7 ldc.i4.s 5 // vectorのvectorの要素数を積む newarr int32 // vectorのvectorを生成 stsfld int32 b // 変数bに格納 ldsfld int32 b // 変数bを読み込み ldc.i4.0 // インデックスを積む ldc.i4.s 3 // vectorの要素数を積む newarr int32 // vectorを生成 // 生成したvectorが値として積まれている stelem.any int32 // 要素に格納 ldsfld int32 b // 変数bを読み込み ldc.i4.0 // インデックスを積む ldelem.any int32 // 要素を読み込む ldc.i4.1 // インデックスを積む ldc.i4.s 11 // 値を積む stelem.any int32 // 要素を格納 ldsfld int32 b // 変数bを読み込み ldc.i4.0 // インデックスを積む ldelem.any int32 // 要素を読み込む ldc.i4.1 // インデックスを積む ldelem.any int32 // 要素を読み込む call void [mscorlib]System.Console::WriteLine(int32) // -> 11 ret }