程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C#銳利體驗(2)

C#銳利體驗(2)

編輯:關於C語言

下面我們來仔細分析上面的代碼和整個程序的編譯輸出及執行過程。先看文件開始的兩行代碼,這是C#語言的單行注釋語句。和C++語言類似,C#支持兩種注釋方法:以"//"開始的單行注釋和以"/*","*/"配對使用的多行注釋。注釋之間不能嵌套。

再來看下面的"using System;"語句,這是C#語言的using命名空間指示符,這裡的"System"是Microsoft.NET系統提供的類庫。C#語言沒有自己的語言類庫,它直接獲取Microsoft.NET系統類庫。Microsoft.Net類庫為我們的編程提供了非常強大的通用功能。該語句使得我們可以用簡短的別名"Console"來代替類型"System.Console"。當然using指示符並不是必須的,我們可以用類型的全局名字來獲取類型。實際上,using語句采用與否根本不會對C#編譯輸出的程序有任何影響,它僅僅是簡化了較長的命名空間的類型引用方式。

接著我們聲明並實現了一個含有靜態Main()函數的HelloWorld類。C#所有的聲明和實現都要放在同一個文件裡,不像C++那樣可以將兩者分離。Main()函數在C#裡非常特殊,它是編譯器規定的所有可執行程序的入口點。由於其特殊性,對Main()函數我們有以下幾條准則:

Main()函數必須封裝在類或結構裡來提供可執行程序的入口點。C#采用了完全的面向對象的編程方式,C#中不可以有像C++那樣的全局函數。

Main()函數必須為靜態函數(static)。這允許C#不必創建實例對象即可運行程序。

Main()函數保護級別沒有特殊要求, public,protected,private等都可,但一般我們都指定其為public。

Main()函數名的第一個字母要大寫,否則將不具有入口點的語義。C#是大小寫敏感的語言。

Main()函數的參數只有兩種參數形式:無參數和string 數組表示的命令行參數,即static void Main()或static void Main(string[]args) ,後者接受命令行參數。一個C#程序中只能有一個Main()函數入口點。其他形式的參數不具有入口點語義,C#不推薦通過其他參數形式重載Main()函數,這會引起編譯警告。

Main()函數返回值只能為void(無類型)或int(整數類型)。其他形式的返回值不具有入口點語義。

我們再來看"HelloWorld.cs"程序中Main()函數的內部實現。前面提過,Console是在命名空間System下的一個類,它表示我們通常打交道的控制台。而我們這裡是調用其靜態方法WriteLine()。如同C++一樣,靜態方法允許我們直接作用於類而非實例對象。WriteLine()函數接受字符串類型的參數"Hello World !",並把它送入控制台顯示。如前所述,C#沒有自己的語言類庫,它直接獲取Microsoft.NET系統類庫。我們這裡正是通過獲取Microsoft.Net系統類庫中的System.Console.WriteLine()來完成我們想要的控制台輸出操作。這樣我們便完成了"Hello World!"程序。

但事情遠沒那麼簡單!在我們編譯輸出執行程序的同時,Microsoft.NET底層的諸多機制卻在暗地裡湧動,要想體驗C#的銳利,我們沒有理由忽視其背靠的Microsoft.NET平台。實際上如果沒有Microsoft.Net平台,我們很難再說C#有何銳利之處。我們先來看我們對"HelloWorld.cs"文件用csc.exe命令編譯後發生了什麼。是的,我們得到了HelloWorld.exe文件。但那僅僅是事情的表象,實際上那個HelloWorld.exe根本不是一個可執行文件!那它是什麼?又為什麼能夠執行?

好的,下面正是回答這些問題的地方。首先,編譯輸出的HelloWorld.exe是一個由中間語言(IL),元數據(Metadata)和一個額外的被編譯器添加的目標平台的標准可執行文件頭(比如Win32平台就是加了一個標准Win32可執行文件頭)組成的PE(portable executable,可移植執行體)文件,而不是傳統的二進制可執行文件--雖然他們有著相同的擴展名。中間語言是一組獨立於CPU的指令集,它可以被即時編譯器Jitter翻譯成目標平台的本地代碼。中間語言代碼使得所有Microsoft.NET平台的高級語言C#,VB.NET,VC.NET等得以平台獨立,以及語言之間實現互操作。元數據是一個內嵌於PE文件的表的集合。元數據描述了代碼中的數據類型等一些通用語言運行時(Common Language Runtime)需要在代碼執行時知道的信息。元數據使得.Net應用程序代碼具備自描述特性,提供了類型安全保障,這在以前需要額外的類型庫或接口定義語言(Interface Definition Language,簡稱IDL)。

這樣的解釋可能還是有點讓人困惑,那麼我們來實際的解剖一下這個PE文件。我們采用的工具是.Net SDK Beta2自帶的ildasm.exe,它可以幫助我們提取PE文件中的有關數據。我們鍵入命令"ildasm /output:HelloWorld.il HelloWorld.exe",一般可以得到兩個輸出文件:helloworld.il和helloworld.res。其中後者是提取的資源文件,我們暫且不管,我們來看helloworld.il文件。我們用"記事本"程序打開可以看到元數據和中間語言(IL)代碼,由於篇幅關系,我們只將其中的中間語言代碼提取出來列於下面,有關元數據的表項我們暫且不談:

class private auto ansi beforefIEldinit HelloWorld
extends [mscorlib]System.Object
{
.method public hidebysig static void Main() cil managed
{
.entrypoint
// Code size 11 (0xb)
.maxstack 8
IL_0000: ldstr "Hello World !"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_000a: ret
} // end of method HelloWorld::Main
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method HelloWorld::.ctor
} // end of class HelloWorld

我們粗略的感受是它很類似於早先的匯編語言,但它具有了對象定義和操作的功能。我們可以看到它定義並實現了一個繼承自System.Object 的HelloWorld類及兩個函數:Main()和.ctor()。其中.ctor()是HelloWorld類的構造函數,可在"HelloWorld.cs"源代碼中我們並沒有定義構造函數呀--是的,我們沒有定義構造函數,但C#的編譯器為我們添加了它。你還可以看到C#編譯器也強制HelloWorld類繼承System.Object類,雖然這個我們也沒有指定。關於這些高級話題我們將在以後的講座中予以剖析。

那麼PE文件是怎麼執行的呢?下面是一個典型的C#/.Net應用程序的執行過程:

用戶執行編譯器輸出的應用程序(PE文件),操作系統載入PE文件,以及其他的DLL(.Net動態連接庫)。

操作系統裝載器根據前面PE文件中的可執行文件頭跳轉到程序的入口點。顯然,操作系統並不能執行中間語言,該入口點也被設計為跳轉到mscoree.dll(.Net平台的核心支持DLL)的_ CorExeMain()函數入口。

CorExeMain()函數開始執行PE文件中的中間語言代碼。這裡的執行的意思是通用語言運行時按照調用的對象方法為單位,用即時編譯器將中間語言編譯成本地機二進制代碼,執行並根據需要存於機器緩存。

程序的執行過程中,垃圾收集器負責內存的分配,釋放等管理功能。

程序執行完畢,操作系統卸載應用程序。

清楚的知曉編譯輸出的PE文件的執行過程是深度掌握C#語言編程的關鍵,這種過程的本身就诠釋著C#語言的高級內核機制以及其背後Microsoft.NET平台種種詭秘的性質。一個"Hello World !"程序的概括力已經足夠,在我們對C#語言有了一個很好的起點之後,下面的專題會和大家一起領略C#基礎語言,窺探Microsoft.Net平台構造,步步體驗C#銳利編程的極樂世界,Let's go!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved