如何编译c ++ / c#/ java不同?

时间:2010-09-08 00:33:32

标签: c# java c++ compiler-construction

我试图了解这些语言是如何工作的。不幸的是,我只读过非常肤浅的东西。 我将总结我已经知道的内容,如果你能纠正我,我会非常高兴,最重要的是,帮助我提高我的一点半知识。

C ++:

C ++编译器预处理所有源文件。这意味着它实际上将字符串插入到最初位于宏的位置。之后,它为包含机器独立字节码的每个源文件创建一个.obj文件。 链接器然后将库中的所有外部.obj文件与定制的.obj文件链接在一起,并将其编译为.exe。

爪哇:

Java代码被编译成机器独立的“字节码”,它位于.class文件中,而后者又可以放在JAR上运行的.JAR文件中。虚拟机正在进行垃圾清理。 Java代码就像C#一样及时编译,但是由SUN开发的热点优化。

C#:

几乎和Java一样? C#源代码被编译成CIL(通用中间语言)代码,这仍然是人类可读的。此代码将由CLR Just-in-Time运行。这种编译只是在首次调用时将方法转换为机器特定的代码。

我实际上对几乎所有语言都感兴趣...但Java和C#几乎相同,我总是想知道如何区分。可以说,C ++是“经典”。两个父亲都没有任何虚拟机。感谢帮助!

编辑:我知道这是一个广泛的主题,但我真的找不到任何扎实的知识。如果你有解释这类事情的链接或书籍,我很乐意去上班。我试着阅读java虚拟机的SUN规范/白皮书,但现在这对我来说有点太深了。

3 个答案:

答案 0 :(得分:6)

非托管C ++的编译与托管C ++,C#和Java的编译非常不同

非托管C ++

非托管C ++(“传统”C ++)直接编译为机器代码。程序员调用针对特定平台(处理器和操作系统)的编译器,并且编译器输出仅在该平台上有效的可执行文件。可执行文件包含特定处理器可以理解的机器代码。执行时,处理器将按原样直接执行编译的代码(模数虚拟内存地址转换yadda yadda)。

托管C ++,C#和Java

托管代码被编译为中间代码(在C#等.NET语言的情况下为CIL,在Java情况下为Java字节代码)。编译器输出包含此中间语言代码的可执行文件。此时,它仍然是平台无关的。执行时,所谓的 Just-in-Time编译器将启动,在执行之前将中间代码转换为机器代码。然后,处理器将执行JIT编译器生成的机器代码。大多数情况下,这个机器代码保存在内存中并在程序结束时丢弃(因此下次必须再次运行JITting),但是存在永久执行JIT的工具。

这里的好处当然是独立于平台的可执行文件可以在任何平台上运行,但缺点是你需要一个执行环境(包括一个JIT编译器)用于该平台。 / p>

答案 1 :(得分:1)

非常好。

C ++的.obj文件取决于机器,但通常没有解析内存地址。链接器只需获取.obj文件并将它们链接在一起,并将许多地址解析为绝对值。

说虚拟机只是在进行垃圾清理 - 甚至不确定这意味着什么,这是不正确的。 VM读取代码字节并对每个代码进行解码,因此VM就像一个CPU。当它发现一堆重复执行的代码时,它可以用真正高度优化的机器代码替换该字节码​​ - 即JIT编译。

我认为其余的都是正确的 - 虽然我不能老实说C#的CIL是否具有人类可读性。

答案 2 :(得分:0)

所有三种语言几乎相同(它们都是必需的OO语言),主要区别在于

  • Java和C#支持运行时类型 反思(即程序可以 检查自身和类型转换是运行时检查操作),而C ++不 和
  • 你无法破坏Java和C# 类型直接来自 语言本身(虽然我 怀疑所有三种语言的编译器只发出代码 中包含未定义的语义 例外情况);
  • C ++不必检查NULL解引用(留给硬件),而C#和Java必须检查每个取消引用的空值;
  • C#和Java必须提供有关内存模型的更强保证(即,在对同一变量进行并发读/写操作时会发生什么),以及异常处理等等;
  • 通常,C ++直接编译为目标机器或汇编语言,而C#和Java通常编译为中间语言(IL或JVM),以便以后进行JIT或解释。 IL和JVM本质上是“CPU”的抽象。

C ++编译器将更加努力地优化它生成的代码,因为它无法将低级优化的优势传递给JIT编译器。