系列文章之三: Array in IL 正如題目所言,這一節我們研究 IL 中的 array (數組)。我們將看到如何定義一個數組,如何查詢數組元數,使用 for 語句" name="description" />
ILMILY: 宋體; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">系列文章之三:
Array in IL
正如題目所言,這一節我們研究IL中的array(數組)。我們將看到如何定義一個數組,如何查詢數組元數,使用for語句和foreach語句的異同。
先來看看我用C#寫的一段程序:
using System;
class array1
{
public static void
{
int [] number;
number = new int [6];
for(int i = 0; i < 6; i++)
{
number[i] = i * i;
}
foreach(int num in number)
{
Console.WriteLine(num.ToString());
}
}
}
這段程序相信大家都看得懂吧(如果看不懂的話最好就別往下看了)。在這段程序中我們看到了C#如何定義一個數組,這和我們以前在C/C++使用的方法不太相同。C#使用了如下兩句,來定義一個數組:
int [] number;
number = new int [6];
而在C/C++中使用一句
int number[6];
就夠了。產生這種差異的緣由何在呢?別慌,馬上就能看到。還有一點,C#中有foreach語句,這個語句與傳統的for語句比較起來又如何呢?看下面,是上面的程序用ildasm反編譯產生的(為了大家能看得更明白,我對反編譯產生的il程序做了一些修改)。
.assembly array1{}
.class private auto ansi beforefieldinit array1
extends [mscorlib]System.Object
{
.method public static void
{
.entrypoint
.maxstack 4
.locals init (int32[] V_0,//int[] number
int32 V_1,//i
int32 V_2,
int32[] V_3,//a pointer of array
int32 V_4)
ldc.i4.6//load int32 const 6(length of the array) onto the stack
newarr [mscorlib]System.Int32//number = new int[6],
//length of the array must be loaded onto the stack before
stloc.0//number
ldc.i4.0//load first local(V_0) onto the stack
stloc.1//int i = 0
br.s loopfor //goto “loopfor”, “loopfor” is only a lable
//startfor is a lable too
startfor: ldloc.0//number
ldloc.1//load V_1 onto the stack
ldloc.1
ldloc.1
mul//multiply
stelem.i4//i = i * i
ldloc.1
ldc.i4.1
add
stloc.1//i = i + 1
loopfor: ldloc.1
ldc.i4.6
blt.s startfor//if i(V_1) less than 6, goto “startfor”
ldloc.0
stloc.3//look it!!
ldc.i4.0
stloc.s V_4
br.s loopforeach
startforeach: ldloc.3
ldloc.s V_4
ldelem.i4
stloc.2
ldloca.s V_2//load address of local_2(V_3)
call instance string [mscorlib]System.Int32::ToString()
//cast int to a new string instance and stord it into local_2
call void [mscorlib]System.Console::WriteLine(string)//print it
ldloc.s V_4
ldc.i4.1
add
stloc.s V_4
loopforeach: ldloc.s V_4//index of V_3[]
ldloc.3
ldlen
conv.i4//conver len to int32
blt.s startforeach
ret//return, must exist, or else the program will stop here
} // end of method array1::Main
}
分析這段程序我們可以看出來定義一個數組的三個步驟,不知你看出了沒有?
1. 定義一個數組指針,int32[] V_0
2. 將數組長度移到堆棧頂,ldc.i4.6
3. 為其分配空間,newarr [mscorlib]System.Int32
這下明白了C#中的數組為什么要通過兩個步驟來定義了吧。其原因就在于在C#中我們是把數組放到托管堆上,而在C++中使用(int number[6])數組不是放在堆上的。IL能做C#不能做到的事情,如數組的下界可以不從0開始等(下次有機會寫個例子J)。
為數組元素賦值,需要四個步驟,
1. 將數組指針移到棧頂,ldloc.0
2. 將數組元素的Index移到棧頂,ldloc.1
3. 將要賦的值移到棧頂(這里是同過mul運算實現),
4. 將值從棧頂移出,賦給元素,stelem.i4
選擇數組元素的方法和上面差不多,只是用不著第3步了,第4步的st換成ld。
對于for語句和foreach語句其實沒有本質的差異。使用foreach語句時,IL會預先產生一個數組指針int32[] V_3,在遍歷數組時再把已知數組的指針賦給這個指針,以后的指令就和for語句相差無幾了。
關于一維數組的用法基本上差不多了,下一次我可能要寫一些關于多維數組和鋸齒數組的內容。
待續……
原文轉自:http://www.anti-gravitydesign.com