約定
//一個典型的用c#寫就的helloworld程序
using system;
class helloworld
{
public static void main()
{
console.writeline("hello world !");
}
}
我忘記自己第一次用c#向世界問好是在什么時候了,不過可以肯定我已經打過招呼了,那時候用的是beta1版。現在你可以到http://msdn.microsoft.com/downloads/default.asp?url=/downloads/sample.asp?url=/msdn-files/027/000/976/msdncompositedoc.xml去下載.net framework software development kit (sdk)的正式版,其中包括了前面提到的.net framework, 以及書寫、編譯、測試、開發(fā) .net framework 應用程序所需要的一切??文檔、例子、命令行工具和編譯器。安裝之后就可以開發(fā)和運行c#程序了,不過一般的建議是:一定要看.net framework sdk中所帶的文檔與例子,如果能照著例子再寫一遍那就再好不過了。
當我第一次看到c#代碼的時候,同樣認為它很像java,一個形象的比喻是:c#和java是一對雙胞胎,從語法的角度來講,它們共同的父親當然非c++莫屬(請注意,不是vc++)。對于一個學過java語言的人來說(比如說在下),要理解這段代碼實在是太容易了:第一行當然是注釋了,c#支持兩種注釋方法,以"http://"開始的單行注釋和以"/*"、"*/"配對使用的多行注釋。第二行(using system)導入了system這個包(在c#中被稱之為名字空間,namespace),可以讓我們方便的調用microsoft.net基類庫system中的所有類,在此例中使用了system名字空間中的"console"類,用于在控制臺窗口輸出程序運行結果。如前所述,c#并沒有內置的輸入輸出語句,所有需實現的功能都完全來自于.net基類庫。這一句的作用就是告訴編譯器去哪里尋找console類以便調用。
接下來聲明了一個類helloworld,這個類中有一個特殊的方法main(),每個可執(zhí)行文件都需要有一個入口點,在c#中,這個入口點就是main()方法,此方法將在程序啟動時被調用。在這個方法中,console是在命名空間system下的一個類,它表示的是控制臺。這里調用其靜態(tài)方法writeline()。如同c++一樣,靜態(tài)方法允許我們直接作用于類而非實例對象。writeline()函數接受字符串類型的參數"hello world !",并把它送入控制臺顯示。如前所述,c#沒有自己的類庫,它直接獲取microsoft.net系統類庫。在這里正是通過獲取microsoft.net系統類庫中的system.console.writeline()來完成我們想要的控制臺輸出操作。現在使用記事本來編寫這段代碼,并將它的文件名保存為helloworld.cs,其中".cs"是c#源代碼文件的擴展名。然后在配置好c#編譯器的命令行環(huán)境里鍵入"csc helloworld.cs"編譯文件。可以看到編譯輸出文件helloworld.exe。鍵入helloworld執(zhí)行這個文件可得到下面的輸出:
hello world !
這就是第一個c#的程序,我們使用csc.exe來編譯它,對于這個c#編譯器,有如下說明:
1. 它是隨.net framework sdk免費發(fā)布的,可以在dos命令行被調用
2. 它的使用方法如下:
csc sourcefile.cs /out:targetfile.exe
如果不使用輸出參數指定目標文件名,則默認輸出為源文件名
3. 一般情況下,它在系統文件夾(windows或winnt)下的microsoft.netframeworkv1.0.3705文件夾內
4. 如果你安裝了vs.net,從visual studio.net tools項目組中可以激活visual studio.net command prompt窗口,這是一個配置好c#編譯器的命令行環(huán)境
5. 使用csc.exe編譯后的c#程序并不是機器代碼(盡管擁有.exe的后綴名)。如前所述,c#程序只是被編譯成了msil代碼。
c#編譯器(csc.exe)編譯后的文件并不是一個嚴格意義上的可執(zhí)行文件(并不包含機器代碼),而是一個pe(portable executable)格式的文件,雖然它同樣擁有.exe的后綴名。在這個pe文件中也不僅僅只包含中間語言,在其中還包含有元數據(metadata)和一個由編譯器添加的目標平臺的標準可執(zhí)行文件頭。
中間語言,確切地說,應該稱為微軟中間語言(microsoft intermediate language,msil),是由微軟定義的一種界于源代碼與機器碼之間的一種語言。在clr中,它首先會由特定的語言編譯器將其包裝成exe格式的偽代碼(p代碼)。再由特定的編譯器將其轉換為本地代碼執(zhí)行。對于微軟中間語言,一個形象的比喻是:如果clr是操作系統的話,那么微軟中間語言就是.net平臺上的asm匯編語言。它比大多數 cpu 機器語言更為高級,比如它可以理解對象類型,并具有創(chuàng)建和初始化對象、調用關于對象的虛擬方法以及直接操作處理數組元素的指令。它甚至還具有發(fā)現和捕獲異常情況用于錯誤處理的指令。
元數據(metadata)和msil共同存在于編譯好的程序文件之中,描述了此程序包含的類型的定義、各種類型的簽名及其它一些數據,相當于以前的類型庫(type library),同時也記載了此程序所引用到的其它外部類。元數據的主要作用是將與代碼有關的更多的信息提供給clr。基本上,元數據用于如下各項任務:用于表示clr用途的信息,如定位和裝載類、內存中這些類的實例、解決調用、翻譯il為原始碼、加強安全并設置運行時上下文邊界。
一個由c#語言寫就的源碼文件在clr環(huán)境中執(zhí)行的過程是這樣的:首先由c#編譯器編譯成包含了中間語言和元數據的pe文件,當我們在系統中調用這個文件時,clr會啟動一個編譯器再將這個pe文件包含的msil代碼轉換成為托管的本地代碼。轉換msil代碼為本地碼的這個編譯器就叫做jit編譯器(just in time,jiter)。請注意它并不是前面我們用到的c#編譯器。
現在讓我們看看jit編譯器是如何工作的:當pe文件被調用時,jie編譯器將其分解為msil和元數據,這時候msil并不直接讓.net去調用本地的系統接口,而是指定.net系統去編譯連接那些需要的clr dll,編譯出百分之百的本地代碼。整個的過程如下:
當一個類型被裝載時,裝載器創(chuàng)建一個存根(stub),并使它與類型的每一個方法相連接。當一個方法第一次被調用時,存根把控制交給jiter。jiter把msil編譯為本地代碼,并且把存根指針指向緩沖本地代碼。已經被jiter編譯的方法隨后就直接調用已經產生的本地代碼,減少了jiter編譯和執(zhí)行代碼的時間。可以看到,jiter并不會一次性的將所有的msil都編譯為本地代碼,而是在我們需要時才即時編譯,也就是說,有些代碼可能從來都沒有被編譯過。很明顯這樣做的好處是既保證了運行期的安全性,又不會損失太多的效率。
這就是一個c#程序執(zhí)行時的步驟。整個過程是這樣的:
1) 由c#編譯器將源代碼編譯為中間語言
2) 裝入托管代碼,這包括解決內存中的名字、表層類(laying out classes ),并且創(chuàng)建jit編譯所必需的存根。通過執(zhí)行經常性校驗,包括加強一些訪問規(guī)則,類裝載器同樣也增強了安全性
3) 用jiter將 il轉換成原始代碼
4) 裝入元數據、校驗類型安全和方法的完整性
5) 垃圾收集(gc)和異常處理
6) 描繪和查錯服務
7) 管理線程和上下文以及遠程管理。
不必全部理解這些概念,在以后的學習中將會一一的體會到它們的精彩,現在你需要做的(如果你還沒這么干過的話),是找到ildasm.exe這個文件(一般情況下,它會和csc.exe在同一文件夾中)。顧名思義,這是一個msil的反匯編程序(.net framework il disassembler),在命令行窗口下輸入ildasm helloworld.exe /out=helloworld.il就會得到兩個文件:helloworld.il和helloworld.res。前者包括了反編譯出來的元數據和msil代碼,后者則是提取的資源文件。用記事本打開helloworld.il文件,可以看到它定義并實現了一個繼承自system.object 的helloworld類及兩個函數:main()和.ctor()。其中.ctor()是helloworld類的構造函數。在這個文件中還包括元數據和其它有關的信息。如果你覺得這樣不夠直觀的話,可以在命令行窗口鍵入ildasm helloworld.exe,這樣就可以啟動ildasm 窗口并向我們展示出反編譯后的helloworld.exe文件。
請仔細將這些代碼看上幾遍,現在理解全部這些內容并不重要,但是希望你也能看一下文件中的元數據,這其中包含所有 runtime 和編譯器需要的有關程序集及其模塊、類型和成員(如方法)的信息。
行文至此,我想談一下學習。如你所知,在我們所處的環(huán)境中,學習總意味著是一個痛苦的過程,學習一種新知識好像總是為了自己的某種需求,我并不認為這樣有什么不對,但我總覺著,除了拿到高薪和受人尊敬外,學習還應該帶給我們更多的快樂。有些知識我們現在也許用不著,比如前面談到的一些內容,但是我們了解了,就是一件值得高興的事。
智慧本身就是好的,有一天我們都會死去,追求智慧的道路還會有人在走著。死掉以后的事我看不到。但在我活著的時候,想到這件事,心里就高興。 ??王小波
今天是2002年4月7號,再過三天就是王小波的忌日了,不知道有多少人還會記得這個日子,還會記得這個人。本文的最后,我向大家推薦小波的作品??每一個心智成熟的人都應該讀一讀小波的文字。在他的雜文隨筆集《沉默的大多數》中有一句話談到了他作為程序員的一面:
“今晚不把這段c++調通,老子就不睡了!”
>>>未完,待續(xù)...
新聞熱點
疑難解答