KEN's .NET

[IL15] 配列を使う 〜 コマンドライン引数を使ってみる

ホーム > KEN's .NET > [IL15] 配列を使う 〜 コマンドライン引数を使ってみる

ここでは.NET Frameworkのアセンブリ言語MSIL(Microsoft Intermediate Language)を使ったプログラミングを紹介します。 読者は.NET プログラミング経験があることを想定しています。

1. はじめに

VB/C#には配列がありますが、ILではどうでしょうか? ILにも1次元配列については専用の命令が用意されています。 今回は、コマンドライン引数からデータを受け取る処理を通じて、 配列の使用方法を紹介します。

2. 配列命令

今回のサンプルで使用する配列関係の命令の一覧を掲載します。 配列の要素の取得にはldelem(load elementの意)で始まる命令を使います。 また、配列の長さ(要素数)を取得するためにldlen(load lengthの意)命令を使います。 ldelem〜命令については、今回使用する命令以外にもよく使いそうなものは抜粋して掲載しました。

表1 配列関係の命令
命令命令書式説明スタック遷移図例外
ldelemldelem typeTok配列arrayからindex番目のtypeTok型の要素をロードする。
.NET Framework 2.0で追加された。
…, array, index → …, valueSystem.NullReferenceException:
arrayがnullの場合。
System.IndexOutOfRangeException:
インデックスが負、配列サイズ以上の場合。
ldelem.i4ldelem.i4配列arrayからindex番目のint32の要素をint32としてロードする。…, array, index → …, value
ldelem.i8ldelem.i8
ldelem.u8
配列arrayからindex番目のint64の要素をint64としてロードする。…, array, index → …, value
ldelem.r4ldelem.r4配列arrayからindex番目のfloat32の要素をF型としてロードする。…, array, index → …, value
ldelem.r8ldelem.r8配列arrayからindex番目のfloat64の要素をF型としてロードする。…, array, index → …, value
ldelem.u4ldelem.u4配列arrayからindex番目のunsigned int32の要素をint32としてロードする。…, array, index → …, value
ldelem.refldelem.ref配列arrayからindex番目のオブジェクト参照の要素をO型としてロードする。…, array, index → …, value
ldlenldlen配列の長さ(native unsigned int)をロードする。…, array → …, lengthSystem.NullReferenceException:
arrayがnullの場合。
※ ldelem〜命令については次の命令の掲載を省略しています。(ldelem.i、ldelem.i1、ldelem.i2、ldelem.u1、ldelem.u2)
※ 配列はすべて1次元で、インデックスは0からはじまります
※ O型は配列の要素型のオブジェクト参照を意味し、F型はネィティブサイズの浮動小数点数型です

3. コマンドライン引数を列挙して表示しよう

図1(UseArray.il)にサンプルプログラム、図2に実行結果の例を掲載しました。

図1 コマンドライン引数を表示するサンプルプログラム
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
.assembly UseArray {}
.method public static void Main(string[] cmdArgs)
{
    .entrypoint
    .maxstack 4
    .locals init(int32 length, int32 i)

    // 配列の要素数の変数lengthへの保存と画面への表示
    ldarg cmdArgs
    ldlen
    stloc length
    ldloc length
    call void [mscorlib]System.Console::WriteLine(int32)
    br CONDITION // 要素数が0の場合を考慮して条件チェックへジャンプ
LOOP:
    // インデックスi : 配列cmdArgsのi番目 を表示
    ldstr "{0}:{1}"
    ldloc i
    box int32
    ldarg cmdArgs
    ldloc i
    ldelem.ref
    call void [mscorlib]System.Console::WriteLine(string, object, object)
INCREMENT:
    // インデックスiをインクリメント(1加算)
    ldloc i
    ldc.i4.1
    add
    stloc i
CONDITION:
    // インデックスが要素数未満かチェック
    ldloc i
    ldloc length
    blt LOOP
    ret
}

> UseArray.exe DJ あいう 123
3
0:DJ
1:あいう
2:123
図2 図1のサンプルの実行結果

ソースを順に追っていきましょう。

  • 2行目、Mainメソッドの定義ですが、今回はコマンドライン引数を受け取るため、 「string[] cmdArgs」でstringの配列変数cmdArgsを定義しています。 C#と同じ記述方法ですが、型(string)の後ろに配列であることを示す[]を加えて配列型を表現します。
  • 9〜13行目で、配列cmdArgsをスタックに置き、ldlen命令でその配列の長さを取得します。 そして、一旦ローカル変数lengthに保存した後、画面に表示します。
  • 配列cmdArgsをスタックに置くと書きましたが、配列もまた参照型ですので、 ヒープ領域にある実体への参照がロードされるという意味です。
  • 14〜34行目は、IL10の回で紹介したFor文の処理の流れになっています。
  • 17〜23行目が、For文の中心的な処理です。
  • 17行目で23行目のWritLineメソッドで第一引数に使う書式文字列をロードします。
  • 18、19行目で23行目ののWritLineメソッドで第二引数に使う配列のインデックスをロードし、ボックス化しておきます。
  • 20行目で配列をロードし、21行目で配列のインデックスをロードし、 22行目のldelemでスタック上の配列とインデックスを利用して、cmdArgs[i]の要素をスタックにロードします。 これは23行目のWritLineメソッドで第三引数に使います。
  • 配列要素のロードにldelem.ref命令を用いていますが、これは配列cmdArgsの要素が参照型のためです。 .NET Framework2.0であれば、ldelem命令を用いて「ldelem string」と記述することもできます。

4. 学んだこと

  • ldelem〜命令で配列の要素をロードできる
  • ldlen命令で配列の長さ(要素数)をロードできる
  • 参照型の配列要素であればldelem.ref命令を使う

A. サンプルダウンロード


ホーム > KEN's .NET > [IL15] 配列を使う 〜 コマンドライン引数を使ってみる

[e-mail] yone_ken00@hotmail.com