编译C++/C#/Java有何不同?

4

我想了解这些语言的底层运作方式,但是我只读过一些表面浅显的东西。 我会总结一下我已经知道的,如果您能纠正我并帮助我增强一点半知不解的认识,我将非常开心。

C++:

C++编译器预处理所有源文件。这意味着它实际上在宏的原始位置插入字符串。之后,它为每个源文件创建一个包含机器无关字节码的.obj文件。 然后,连接器将来自库的所有外部.obj文件与自定义制作的.obj文件链接在一起,并将其编译成.exe。

Java:

Java代码被编译成机器无关的“字节码”,这些字节码位于.class文件中,这些文件可以位于.JAR文件中,在JRE上运行。虚拟机只需执行垃圾回收。Java代码类似于C#进行即时编译,但使用由SUN开发的热点优化。

C#:

与Java几乎相同吗? C#源代码被编译为CIL(公共中间语言)代码,该代码仍然可读。此代码将由CLR Just-in-Time运行。此编译将方法转换为机器特定代码,仅在首次调用它们时执行。

我实际上对几乎每种语言都感兴趣......但是Java和C#几乎相同,我一直想知道它们的区别。而C ++则是“经典”,没有任何虚拟机。非常感谢您的帮助!

编辑:我知道这是一个广泛的主题,但我真的找不到任何实质性的知识。如果您有解释这种东西的链接或书籍,我很乐意去研究。我尝试阅读SUN的Java虚拟机规范/白皮书,但那对我来说有点深奥。


1
不确定问题是什么... - Mitch Wheat
大部分都是正确的。但问题似乎在描述中被遗漏了。能否澄清一下? - Vineet Reynolds
在编译 C#/Java/C++ 代码并运行之间的过程中会发生什么?@Vineet:有什么问题吗?你说“大多数”。 - Blub
你到底在问什么?它们的区别并不真正在于它们如何编译,而是在语言本身上,在Java/C#的情况下,则在于它们如何被解释。 - EboMike
@Blub,Java字节码是Java编译器生成的可执行文件的标准化表示形式。它的标准化程度足以让任何JVM都能够获取字节码并执行它。不确定微软世界存在多少标准化。 - Vineet Reynolds
显示剩余3条评论
3个回答

6

非托管C++的编译方式与托管C++、C#和Java的编译方式非常不同

非托管C++

非托管C++(“传统”C++)直接编译成机器码。程序员调用针对特定平台(处理器和操作系统)的编译器,编译器输出一个仅在该平台上运行的可执行文件。可执行文件包含特定处理器理解的机器码。执行时,处理器将直接执行已编译的代码(除了虚拟内存地址翻译等等)。

托管C++、C#和Java

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

当然,这里的好处是跨平台的可执行文件可以在任何平台上运行,但缺点是您需要为该平台准备一个执行环境(包括JIT编译器)。


3
请注意,Java语言规范中没有规定必须将Java编译为JVML。实际上,有许多Java的实现方式并不是这样。它们会编译成CIL、本机代码、Parrot字节码、ECMAScript、Dalvik字节码或C等。某些Java的实现方式是纯解释器。同样对于C#,也有可以编译成本机代码的编译器。对于C ++,有些解释器根本不进行编译,而有些编译器会将其编译为Java或ECMAScript。实际上,编译器编译的内容与语言无关,只是编译器自己的业务。 - Jörg W Mittag

1

非常好。

C++的.obj文件是机器相关的,但通常不会解析内存地址。链接器只需将.obj文件链接在一起,并将许多地址解析为绝对值。

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

我认为其余部分都相当正确--尽管我无法诚实地说C#的CIL是否可读。


你的意思是它将机器无关地址(如指向I/O的虚拟指针)解析为Windows上的实际内容,对吗?这与我早些时候读到的某些内容相当。 - Blub
@Blub 实际上,它解析可能指向另一个目标文件的地址——在编译时,目标文件互相不知道对方存在,也不知道入口点最终会在哪里。当链接器将所有目标文件放在一起时,它会解析直到那时才能知道的地址(如果目标文件以不同的顺序链接会怎么样呢?)。C#和Java不需要这样做,因为它们实际上在字节码中存储了方法的名称,并让运行时来处理。 - Bill K

0

这三种编程语言基本相同(它们都是命令式面向对象语言),主要区别在于:

  • Java 和 C# 支持运行时类型反射(即程序可以检查自身,并进行类型转换),而 C++ 不支持;
  • 你不能直接从 Java 和 C# 语言内部曲解类型(虽然我怀疑这三种语言的编译器只是在异常情况下发出未定义语义的代码);
  • C++ 不必检查空指针引用(留给硬件处理),而 C# 和 Java 必须在每次引用处检查 null;
  • C# 和 Java 必须提供更强的内存模型保证(即在并发读写同一变量时会发生什么),以及异常处理等方面的保证;
  • 通常,C++ 直接编译为目标机器或汇编语言,而 C# 和 Java 通常编译为中间语言(IL 或 JVM),以便稍后进行 JIT 编译或解释。IL 和 JVM 本质上是“CPU”的抽象。

C++ 编译器将会更加努力地优化生成的代码,因为它无法将底层优化的责任推给 JIT 编译器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接