程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> 淺談Microsoft C#編譯器和Mono C#編譯器

淺談Microsoft C#編譯器和Mono C#編譯器

編輯:關於C#

我在2009年4月19日寫的一篇隨筆“Timus 1037. Memory management”中,使用了如下的一個結構(Structs)來表示“內存塊”:

struct Block
{
 public int Id { get; private set; }
 public int Time { get; set; }
 public Block(int id, int time) : this() { Id = id; Time = time; }
}

在這個結構中,Id 表示“內存塊”的編號,Time 表示該“內存塊”到期時間,它們都是自動實現的屬性(Auto-Implemented Properties)。

下面,就是我們這次的主角 Block.cs 源程序文件:

using System;

namespace Skyiv.Ben.Test
{
 struct Block
 {
  public int Id { get; private set; }
  public int Time { get; set; }
  public Block(int id) : this() { Id = id; }
 }
 
 sealed class Test
 {
  static void Main()
  {
   Console.WriteLine(new Block(37).Time);
  }
 }
}

我們將分別在 Windows 和 Linux 操作系統下編譯這個 C# 源文件。

Windows 操作系統的版本如下所示:

編譯器是:

E:\work> csc –out:block.windows.exe block.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.

E:\work>

Linux 操作系統和編譯器如下所示:

ben@linux-cod2:~/work> cat /etc/issue
Welcome to openSUSE 11.1 - Kernel \r (\l).

ben@linux-cod2:~/work> uname -srvm
Linux 2.6.27.21-0.1-default #1 SMP 2009-03-31 14:50:44 +0200 x86_64
ben@linux-cod2:~/work> mono --version
Mono JIT compiler version 2.4 (tarball Fri Mar 13 15:52:25 UTC 2009)
Copyright (C) 2002-2008 Novell, Inc and Contributors. www.mono-project.com

TLS:      __thread

GC:      Included Boehm (with typed GC)

SIGSEGV:    altstack

Notifications: epoll

Architecture: amd64

Disabled:   none
ben@linux-cod2:~/work> gmcs --version
Mono C# compiler version 2.4.0.0
ben@linux-cod2:~/work> gmcs -out:block.mono.exe block.cs
ben@linux-cod2:~/work> 

下面就是在這兩個操作系統下分別編譯後的結果:

E:\work>dir
 Volume in drive E is Data2
 Volume Serial Number is 16BB-989E

  Directory of E:\work

2009/05/08 21:21  <dir>     .
2009/05/08 21:21  <dir>     ..
2009/05/08 20:02        318 block.cs
2009/05/08 20:10       3,584 block.mono.exe
2009/05/08 21:21       4,096 block.windows.exe
        3 File(s)     7,998 bytes
        2 Dir(s) 61,416,194,048 bytes free

E:\work>

在 Windows 操作系統上編譯後的程序可以在 Linux 操作系統下運行,反之亦然。

在 Windows 操作系統下運行:

E:\work> block.windows.exe
0
E:\work> block.mono.exe
0
E:\work>

在 Linux 操作系統下運行:

ben@linux-cod2:~/work> mono block.windows.exe
0
ben@linux-cod2:~/work> mono block.mono.exe
0
ben@linux-cod2:~/work> 

下面,我們用 ildasm 來反匯編這兩個 .exe 文件。

從上圖中可以看出,這兩個 .exe 文件中的內容幾乎是一樣的,除了 Block 結構的 Id 和 Time 屬性用 Microsoft C# 編譯器比用 mono C# 編譯器多了個 instance 修飾符。

下面就是 Block 結構的 Id 屬性(總是先 Microsoft 後 mono,下同):

下面就是 Block 結構的 Id 屬性的 get 方法:

從上圖中可以看出,Microsoft C# 編譯器生成的代碼有很多不必要的 IL 代碼,不好。注意,上述代碼是直接用 csc.exe 編譯的,在編譯時沒有加上 /debug+ 參數,而不是在 Visual Studio 2008 IDE 中編譯的。

而 mono C# 編譯器生成的代碼就非常好,沒有多余的 IL 代碼。

下面就是 Block 結構的 Id 屬性的 set 方法:

這下,Micorsoft 和 mono 生成的代碼又完全一樣,奇怪。

下面就是 Block 結構的構造函數:

從上圖中可以看出,Microsoft 生成的代碼除了有多余的 nop 以外,還多了以下一行:

IL_0001: initobj  Skyiv.Ben.Test.Block

這一行代碼,是用來調用 Block 結構的默認(無參的)構造函數,對應下面 C# 源程序代碼:

public Block(int id) : this() { Id = id; }

中的“ : this() ” 。

如果刪除這個“ : this() ” ,用 Microsoft C# 編譯器編譯時就會出錯,如下所示:

E:\work2> csc block.cs
適用於 Microsoft(R) .NET Framework 3.5 版的 Microsoft(R) Visual C# 2008 編譯器 3.5.30729.1 版
版權所有(C) Microsoft Corporation。保留所有權利。

block.cs(9,28): error CS0188: 在給“this”對象的所有字段賦值之前,無法使用該對象
block.cs(9,12): error CS0843:
    必須對自動實現的屬性“Skyiv.Ben.Test.Block.Id”的支持字段完全賦值,才能
    將控制返回給調用方。請考慮從構造函數初始值設定項中調用默認構造函數。
block.cs(9,12): error CS0843:
    必須對自動實現的屬性“Skyiv.Ben.Test.Block.Time”的支持字段完全賦值,才
    能將控制返回給調用方。請考慮從構造函數初始值設定項中調用默認構造函數。

E:\work2> 

但是,如果用 mono C# 編譯器編譯就可以順利通過。實際上,即便加上這個“ : this() ” ,mono C# 編譯器也完全無視它,也就是說,即使在有“ : this() ” 的情況下,mono C# 編譯器也不會生成調用  Block 結構的默認構造函數的 IL 代碼,它直接忽略了這個“ : this() ”。而且,這樣做也沒有造成什麼不良後果,block.mono.exe 在 Windows 和 Linux 操作系統下都運行良好。

最後,block.cs、block.windows.exe 和 block.mono.exe 這三個文件可以在這裡下載。

實際上,之所以會寫這篇文章,是因為我在做“Timus 1037. Memory management”這道 ACM 題的時候,是在 Ubuntu 9.04 Linux 下使用 MonoDevelop 2.0 寫程序的,如下所示:

從上圖中可以看出,在 Block 結構的構造函數中沒有“ : this() ” ,這在 Linux 下運行得很好。但是,提交到 ACM 網站後,由於該網站是使用 Microsoft Visual C# 2008 версии 3.5.30729.1 編譯器,導致編譯出錯。

這就引起了我比較 Microsoft C# 編譯器和 mono C# 編譯器的興趣,於是就產生了這篇文章。

總結一下,我認為目前的 mono C# 編譯器生成的代碼比較高效,而 Microsoft C# 編譯器生成的代碼有很多不必要的垃圾。

以上觀點如有不妥之處,歡迎各位大俠指正。

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