这听起来像是个非常高大上的名字,上学的时候我们学过的编译原理或者编译技术实际上是在讲如何将高级程序语言如C++编译为计算机可以理解的汇编语言,这里说的编译原理只是想说明在.NET的世界里编译这件事儿和传统的C++有什么区别和联系。先来简单的说一下传统的做法,在C++里,但你编译一个应用程序比如一个EXE文件或者是DLL(注意这里的DLL叫做动态链接库,只是到了.NET中才才被叫做程序集)时,实际上编译器做的事情就是直接将你写的C++代码编译为汇编语言,然后以二进制的形式存放在EXE或者DLL文件中,当被执行的时候,CPU就可以直接读到汇编代码开始运行了。当然说起来简单,里面还是有非常多的细节问题,我们需要关注的重点是,C++编译器做到的事情是将高级语言直接编译为汇编语言。

接下来,我们来看一看在.NET中我们如何处理。在说明之前,我们来回顾一下一个非常经典的说法,你看任何一本介绍.NET的书都会在开篇宣称.NET是跨平台跨语言的高级运行时,但是.NET是如何做到的呢?我们引入一个非常关键的概念叫做Intermediate Language简称IL,中文叫做中间语言。

当你写了一段程序(假设是一个Console Application EXE的项目),在Visual Studio中点击F5编译并运行这个按钮的时候,实际上都发生了些什么呢?

  1. 首先是编译,与C++类似,.NET编译器也是将高级语言编译,但是输出并不是汇编语言,而是IL中间语言。这个所谓的IL是个什么东西呢?你可以理解为,这是和C#类似的一种语言,程序员可以很容易的看懂甚至直接用Visual Studio就可以写。然后这些中间语言会以二进制的形式存放在EXE文件中。
  2. 接下来是运行。运行的时候.NET Runtime会加载EXE中的必要信息以及IL,这时你可能会问,C++运行的时候,CPU可以直接运行汇编,但是CPU能认识IL么?答案是否定的,CPU会IL一无所知。.NET运行时会进行二次编译,将IL编译为真正的汇编语言,然后CPU执行。

注意,.NET的程序要运行,实际上是需要两次编译的,一次是在开发的时候,另外一次则是在运行的时候。那么这样做实际上解决了.NET跨语言跨平台这个问题。.

NET上会很多种语言,比如C#,VB.NET, C++.NET, F#,这些语言开发出来的程序,只要机器上装了.NET Framework就都可以运行,这是因为不同的语言在第一次(开发过程)编译的时候都会被编译为IL,也就是说,同样的一个功能,用C#写出来和F#写出来编译出来的IL是一样的(当然编译器可能根据不同的高级语言特点有所优化,但是基本一致)。这样做的好处是什么呢?很简单,比如你用C#写了一个feature,我用F#加载你的DLL就可以使用你的程序集了。这看起来没什么,但是你能想想一下如果C++可以非常简单的调用Java的类库,这个世界是不是就该疯狂了?再来是跨平台,当你的.NET程序运行的时候,.NET运行时负责将IL编译为汇编语言,在运行编译时,.NET可以根据当前运行的操作系统以及CPU构架的不同生成完全不一样的汇编语言。但是C++就做不到,你用一种编译器编译出来的东西只能运行在某个特定的平台上,比如VC编译器编译出来的只能跑在windows上,在linux上就完蛋了。这是.NET非常重要的一个框架技术核心,虽然现在被应用的并不广泛,因为除了C#和Windows平台意外,.NET是很少被使用的。但是如果未来微软将.NET技术推广到更多领域,这种跨平台跨语言的框架核心就能显示出价值了。看一下下面这个图。

接下来我们来看几个非常重要的相关的面试问题

首先,二次编译带来的性能损失。这很容易理解,与C++相比,运行.NET程序在运行的时候多了一次编译,这肯定是要慢的。.NET runtime做了一些性能的优化,即由IL编译过的汇编语言会被缓存起来,当第二次再遇到同样的IL的时候,会直接从内存中加载,而不再被编译。这也就是.NET程序会被指责第一次运行极慢无比的一个重要原因。比如我们来看看下面这段code...

Console.WriteLine("Hello world"); // first time, compile this function

Console.WriteLine("Hello world again"); // second time, load from cache

当然为了提高性能,.NET编译器允许将高级语言如C#直接编译为汇编语言,但是并不推荐这样做,这样的会,所有跨平台,跨语言的特性就将消失,这种做法适用于对性能要求极高的应用程序。

第二,反编译的故事。所有.NET的DLL都是中间语言组成的,所以,你可以用反编译器加载DLL,由中间语言反编译为C#以此看到其他程序集的源代码。当然.NET提供了加密保护机制,当你编译为DLL的时候可以加入扰码,使反编译器无法理解IL。

第三,这是反射的基础。你肯定知道反射的故事,在运行时可以动态的加载某个类型中所有的property, field等等,.NET就是通过分析中间语言做到这一点的。在运行时,.NET runtime会加载IL并理解所有的类型定义。

好了,这就是所有.NET编译的基本故事了,虽然说和你写code没什么太大关系吧,作为.NET的核心技术框架,这个还是要了解一下的。That's much for today. 

.net 编译原理的更多相关文章

  1. 编译原理-词法分析05-正则表达式到DFA-01

    编译原理-词法分析05-正则表达式到DFA 要经历 正则表达式 --> NFA --> DFA 的过程. 0. 术语 Thompson构造Thompson Construction 利用ε ...

  2. 跟vczh看实例学编译原理——三:Tinymoe与无歧义语法分析

    文章中引用的代码均来自https://github.com/vczh/tinymoe.   看了前面的三篇文章,大家应该基本对Tinymoe的代码有一个初步的感觉了.在正确分析"print ...

  3. 跟vczh看实例学编译原理——二:实现Tinymoe的词法分析

    文章中引用的代码均来自https://github.com/vczh/tinymoe.   实现Tinymoe的第一步自然是一个词法分析器.词法分析其所作的事情很简单,就是把一份代码分割成若干个tok ...

  4. 跟vczh看实例学编译原理——一:Tinymoe的设计哲学

    自从<序>胡扯了快一个月之后,终于迎来了正片.之所以系列文章叫<看实例学编译原理>,是因为整个系列会通过带大家一步一步实现Tinymoe的过程,来介绍编译原理的一些知识点. 但 ...

  5. 跟vczh看实例学编译原理——零:序言

    在<如何设计一门语言>里面,我讲了一些语言方面的东西,还有痛快的喷了一些XX粉什么的.不过单纯讲这个也是很无聊的,所以我开了这个<跟vczh看实例学编译原理>系列,意在科普一些 ...

  6. 编译原理-词法分析04-NFA & 代码实现

    编译原理-词法分析04-NFA & 代码实现 0.术语 NFA 非确定性有穷自动机nondeterministic finite automation. ε-转换ε-transition 是无 ...

  7. .NET程序的简单编译原理

    1.不管是什么程序,最终的执行官是CPU,而CPU只认识1和0的机器码. 2.我们现在写的一般是高级语言写的程序.CPU是不认识我们用高级语言写的源代码的,那应该怎么办才能让CPU执行我们写好的程序尼 ...

  8. Atitit.编译原理与概论

    Atitit.编译原理与概论 编译原理 词法分析 Ast构建,语法分析 语意分析 6 数据结构  1. ▪ 记号 2. ▪ 语法树 3. ▪ 符号表 4. ▪ 常数表 5. ▪ 中间代码 1. ▪ 临 ...

  9. 编译原理简单语法分析器(first,follow,分析表)源码下载

    编译原理(简单语法分析器下载) http://files.cnblogs.com/files/hujunzheng/%E5%8A%A0%E5%85%A5%E5%90%8C%E6%AD%A5%E7%AC ...

  10. 编译原理(简单自动词法分析器LEX)

    编译原理(简单自动词法分析器LEX)源程序下载地址:  http://files.cnblogs.com/files/hujunzheng/%E6%B1%87%E7%BC%96%E5%8E%9F%E7 ...

随机推荐

  1. transport.js报hasOwnProperty对象不支持此属性

    ECShop transport.js错误 这次出现的问题是transport.js在IE下提示对象不支持该用法.出现错误位置为608行的下面的代码: if(this.hasOwnProperty(k ...

  2. EffectiveJava(27)优先考虑使用泛型方法

    泛型方法也可以从泛型类中获得同等收益,泛型方法的转换也十分简单,只需将原生态类型改为泛型,基本就可以解决问题 如:一个返回两个集合的联合 public static Set union(Set s1, ...

  3. LightOj 1221 - Travel Company(spfa判负环)

    1221 - Travel Company PDF (English) Statistics problem=1221" style="color:rgb(79,107,114)& ...

  4. 算法笔记_107:蓝桥杯练习 算法提高 学霸的迷宫(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 学霸抢走了大家的作业,班长为了帮同学们找回作业,决定去找学霸决斗.但学霸为了不要别人打扰,住在一个城堡里,城堡外面是一个二维的格子迷宫,要 ...

  5. 算法笔记_068:Dijkstra算法简单介绍(Java)

    目录 1 问题描述 2 解决方案 2.1 使用Dijkstra算法得到最短距离示例 2.2 具体编码   1 问题描述 何为Dijkstra算法? Dijkstra算法功能:给出加权连通图中一个顶点, ...

  6. 修改HTML5 input placeholder默认颜色

    WebKit和Blink(Safari,Google Chrome, Opera15+)使用伪元素 ::-webkit-input-placeholder Mozilla Firefox 4-18使用 ...

  7. 安卓camera拍照时序

    转自:http://blog.csdn.net/tankai19880619/article/details/17147125 一.看看调用时序图 1.拍照命令时序图 2.拍照数据回调时序图 二.看看 ...

  8. Android源代码装饰模式---ContextWrapper

    假设说Android源代码中哪个地方装饰模式应用的最明显的话,那肯定是非ContextWrapper莫属了,ContextWrapper是一个透明的经典的装饰模式.本文将通过装饰器模式分析Contex ...

  9. Ubuntu 18.04修改IP地址

    注:配置/etc/network/interfaces已无用 root@ubuntu:~# vim /etc/netplan/50-cloud-init.yaml network: ethernets ...

  10. 在go中使用leveldb --levi

    github上有个比较好用的leveldb go wrapperlevigo, 安装之前需现在机器上安装leveldb 当前版本的LevelDB没有带安装脚本,需自行编译安装,过程如下: instal ...