非托管 C/C++可以在底层控制系统,能精确地按照自己的需要来管理内存, 很容易创建线程等等.VB6允许你快速地构建UI应用程序,很容易控制COM对象和数据库.
CLR正像其名字那样, runtime被很多不同的编程语言使用, CLR的feature对任何以CLR为目标的编程语言都是使用的.例如, runtime使用异常来报告错误, 因此所有的语言都是通过异常来报告错误的. 另外一个例子是runtime允许你创建一个线程,因此所有的语言都可以创建线程.
实际上, 在runtime时, CLR并不知道开发者使用了什么编程语言, 这意味着你应该选择更容易表达你的目的编程语言, 只要你使用的编译器是以CLR为目标的.
所以, 如果我说的是正确的话, 那么使用一种语言比另一种语言的先进之处是什么呢? 我把编译器看作是语法检查器或者代码纠正分析器, 它们检查你的源代码, 确保你写的代码有意义, 然后输出表达你的意愿的代码. 不同的编程语言允许你用不同的语法开发, 不要低估这种选择的价值,对于数学或者商业上的应用程序, 和使用Perl语法相比, 使用APL语法来表达你的意愿能够节约不少开发的时间.
微软已经创建了几个语言编译器(以runtime为目标的): C++/CLI, C#, VB, Jscript, J#和一个中间语言(IL)汇编器. 除了微软, 一些其他公司, 大学也创建了以CLR为目标的编译器. 我注意到的编译器有Ada, APL, Caml, COBOL, Eiffel, Forth, Fortran, Haskell, Lexico, LISP, LOGO, Lua, Mercury, ML, Mondrian, Oberon, Pascal, Perl, Php, Prolog, Python, RPG, Scheme, Smalltalk, Tcl/Tk.
下图给出了编译原文件的过程, 从图中可以看出,你可以用支持CLR的任何编程语言创建原文件, 然后你使用对应的编译器来检查语法和分析源代码. 不管你使用什么编译器, 编译的结构都是托管模块. 一个托管模块是一个标准的32-bit微软Windows portable executable (PE32) 文件或者标准的64-bit Windows portable executable (PE32+) 文件, 它们需要CLR来执行。
下表描述了托管模块的各个部分:
各个部分 |
描述 |
PE32 or PE32+ header |
标准的Windows PE文件头, 它和Common Object File Format (COFF) header相似. 如果使用PE32格式, 那么文件将运行在32-bit或者64-bit版本的Windows上. 如果使用PE32+格式, 文件需要64-bit版本的Windows来运行. 这个头也指明了文件的类型: GUI, CUI 或者 DLL, 还包含着时间戳信息来表明文件构建的时间. 对于只包含IL代码的mudule, 该信息块被忽略. 对于包含native CPU代码的模块, 这个header包含了关于native CPU代码的信息. |
CLR header |
包含着使其成为托管模块的信息. 这个header包含了需要CLR的版本, 一些标志, 托管模块的入口方法(main方法)的MethodDef metadata符号, 和matadata, 资源, strong name, 标志, 和其它不太有意义成员的位置/大小. |
Metadata |
每个托管模块都包含着metadata表, 有两类主要的表: 描述你的源代码中的类型和成员的表, 描述你的源代码所引用的类型和成员的表. |
IL code |
编译器编译元代码所产生的代码, 在runtime时, CLR将编译IL为native CPU指令. |
Native代码编译器产生的代码是针对特定的CPU架构的, 例如x86, x64或者IA64. 所有的CLR兼容的编译器都产生中间语言(IL)代码, IL代码有时候也称为托管代码, 因为CLR管理它的执行过程.
除了产生IL, 每个以CLR为目标的编译器都要为每个托管模块产生完整的metadata. 简单地说, metadata是一组数据表格, 其描述了模块中定义的内容, 例如类型和它们的成员. 此外, metadata还包括它所管理的模块引用, 例如导入的类型和它们的成员. Metadata是原有技术(例如类型库Type Library和接口定义语言IDL文件)的超集. 要注意的重要事情是CLR metadata的信息更加完整. 不像类型库和IDL, metadata总是和包含IL代码的文件相关联. 实际上, metadata总是作为代码嵌入相同的EXE/DLL中, 使得很难将其分离出来. 因为编译器是同时产生metedata和代码, 并将它们绑定到最终的托管模块, metadata和它所描述的IL代码永远都不需要互相同步.
Metadata有很多用途, 下面是其中的一些:
微软的C#, VB, JScript, J#和IL汇编器总是产生包含托管代码 (IL)和托管 data (垃圾回收的数据类型)的模块. 终端用户必须安装CLR (目前是作为.NET Framework的一部分发布的), 来执行包含托管代码和/或托管数据的模块. 这和运行MFC或者VB6应用程序所需要的MFC类库或者VB DLL一样.
默认地, 微软的C++编译器build的EXE/DLL模块只包含非托管代码和数据. 这些模块不需要CLR就能执行. 然而, 通过指定/CLR命令行开关, C++编译器可以产生包含托管代码的模块, 当然必须安装CLR才能执行代码. 上面所提到的所有的微软编译器中, C++是最特殊的, 因为它是唯一的编译器允许开发者既能写托管代码, 也能写非托管的代码, 并将它们放到一个模块中. 也只有微软的编译器才能允许开发者在他们的源代码中既能定义托管的数据类型, 也能定义非托管的数据类型. 微软C++编译器所提供的灵活性远超过其它的编译器, 因为它允许开发者用托管代码编写应用程序, 然后在非托管的C++代码中访问它们.