浅谈 Microsoft C# 编译器和 Mono C# 编译器

news/2024/7/9 18:24:14 标签: c#, 操作系统, epoll

我在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 操作系统的版本如下所示:

Vista.png

编译器是:

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 操作系统和编译器如下所示:

openSUSE.png
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 文件。

ildasm-1.png

从上图中可以看出,这两个 .exe 文件中的内容几乎是一样的,除了 Block 结构的 Id 和 Time 属性用 Microsoft C# 编译器比用 mono C# 编译器多了个 instance 修饰符。

下面就是 Block 结构的 Id 属性(总是先 Microsoft 后 mono,下同):

ildasm-2.png
ildasm-3.png

下面就是 Block 结构的 Id 属性的 get 方法:

ildasm-6.png
ildasm-7.png

从上图中可以看出,Microsoft C# 编译器生成的代码有很多不必要的 IL 代码,不好。注意,上述代码是直接用 csc.exe 编译的,在编译时没有加上 /debug+ 参数,而不是在 Visual Studio 2008 IDE 中编译的。

而 mono C# 编译器生成的代码就非常好,没有多余的 IL 代码。

下面就是 Block 结构的 Id 属性的 set 方法:

ildasm-8.png
ildasm-9.png

这下,Micorsoft 和 mono 生成的代码又完全一样,奇怪。

下面就是 Block 结构的构造函数:

ildasm-4.png
ildasm-5.png

从上图中可以看出,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 写程序的,如下所示:

MonoDevelop.png

从上图中可以看出,在 Block 结构的构造函数中没有“ : this() ” ,这在 Linux 下运行得很好。但是,提交到 ACM 网站后,由于该网站是使用 Microsoft Visual C# 2008 версии 3.5.30729.1 编译器,导致编译出错。

这就引起了我比较 Microsoft C# 编译器和 mono C# 编译器的兴趣,于是就产生了这篇文章。

 

总结一下,我认为目前的 mono C# 编译器生成的代码比较高效,而 Microsoft C# 编译器生成的代码有很多不必要的垃圾。

以上观点如有不妥之处,欢迎各位大侠指正。


http://www.niftyadmin.cn/n/1296393.html

相关文章

C#.NET实现经典排序算法

1、选择排序 选择排序class SelectionSorter { private int min; public void Sort(int[] arr) { for (int i 0; i < arr.Length - 1; i) { min i; for (int j i 1; j < arr.L…

第 4 章:配置网络环境

返回课程列表 目的 本章帮助您配置和管理网络环境&#xff0c;以便用户能够访问数据库。 主题 本章讨论了以下内容&#xff1a; 使用 Enterprise Manager Net Services Administration 页面利用 Enterprise Manager 启动监听器利用监听器控制实用工具启动监听器 配置本地命名&a…

SERPENT算法学习心得

本文原创&#xff0c;转载请注明出处。douqinglgmail.com1. 概述 由于工作的原因&#xff0c;我学习了SERPENT算法&#xff08;注释1&#xff09;&#xff0c;并进行了软件实现&#xff0c;抓取了每一轮、每一步操作的中间数据&#xff0c;在此分享给大家。首先&#xff0c;…

客户端无法找到共享打印机

例4&#xff1a;客户端无法找到共享打印机 疑问&#xff1a;客户端在正常安装了网络打印机后&#xff0c;为何在“网上邻居”中找不到此设备&#xff0c;而共享打印机列表中只出现“Microsoft Windows Network”的信息&#xff1f;分析与解决&#xff1a;这是在共享网络打印中常…

SPI接口扫盲 SPI定义/SPI时序(CPHA CPOL)

SPI接口扫盲 douqinglgmail.com为何要写这篇文档&#xff1f; 百度上找出来的SPI接口中文描述都说的太过简略&#xff0c;没有一篇文档能够详尽的将SPI介绍清楚的。wikipedia英文版[注释1]中&#xff0c;SPI接口介绍的很好&#xff0c;但是毕竟是英文版&#xff0c;读起来终究不…

DevOps实现自动化发布实操

DevOps实现自动化发布流程 本篇文章来自 B站视频&#xff08;部分步骤与视频存在差异&#xff09; 流程图及原理 本地编写代码提交至远程仓库Jenkins&#xff08;基于Docker&#xff09;通过内置Git获取提交的代码&#xff0c;通过Maven进行打包&#xff0c;形成可执行文件&a…

5月第2周编辑部标题训练:寻找读者最关注的新闻点

前几期我们的标题都是寻找原标题中的一些缺憾。本期不算&#xff0c;因为这个标题已经基本上还算不错了……【原标题】哪种程序员最幸福&#xff1f;编程语言快乐指数榜【原文地址】http://developer.51cto.com/art/200905/123656.htm这篇文章是由51CTO.com开发频道编辑阿菜通过…

c问题---关于数组溢出的思考

逛CSDN看到这么一个问题&#xff1a; c问题---关于数组溢出的思考 今天在做题时&#xff0c;发现定义整型数组a[10],并赋初值&#xff0c;然后我访问a[11],输出0&#xff0c;再a[11]3后访问a[11],输出3&#xff0c;a的长度还是10&#xff0c;那么a[11]存在哪里了&#xff1f;…