【问题标题】:How does C differ from Java's compilation model?C 与 Java 的编译模型有何不同?
【发布时间】:2011-11-28 15:06:15
【问题描述】:

经典编译模型(C、C++等)和Java编译模型有什么区别?

【问题讨论】:

  • 嗯,你知道 C还是C++?
  • 什么?你的意思是编译成机器码和编译成jvm字节码的区别?详细说明。
  • 这是作业吗?看起来你好像停在句子中间,开始输入一个新的,即从问题列表中复制。
  • @iMohammad:你倒退了。 C 是编程的支柱,在每台机器上使用以提供基础。 Java 仅在一小部分计算机上可用。
  • @iMohammad:Java 实际上并不能在“地球上的每一种机器”上运行。为了让 Java 在特定平台上运行,需要有一个为该平台编写的虚拟机,或者一个能够从该平台的 Java 字节码创建机器代码的 Java 编译器。

标签: java c++ c


【解决方案1】:

正确回答您的问题可能需要数百页才能回答,但我会尝试用几段来总结。

基本上,您所指的“经典编译模型”将人工编写的源代码作为输入并发出机器代码,无需进一步翻译机器代码即可加载和运行。这样做的一个后果是生成的机器代码只能在兼容的硬件上运行,并且只能在兼容的操作系统中运行。

Java 编译模型以人工编写的源代码作为输入,发出的不是机器代码,而是所谓的“byte code”。字节码不能直接在机器上执行。相反,它需要由另一个编译器再次翻译成机器代码,或者由在机器上执行与字节码中的指令相对应的指令的设备即时解释。后一种设备通常称为虚拟机。该模型的一个分支是字节码可以在任何具有字节码编译器或为其编写的虚拟机的平台上“运行”。这为 Java 提供了完全可移植性的外观和效果,而 C++ 编译器堆栈发出的机器代码并不暗示这种可移植性。

【讨论】:

  • 不讨论字节码与机器码编译的任何性能影响是多么明智;)
  • @larsmans:是的,我绝对不想走那条路。 :)
  • @JohnDibling 不是。有一些特殊的工具可以生成机器代码,但很少使用。通常的 java 编译器(javac、eclipse、..)除了字节码之外不能生成任何东西,而且根本不是很复杂。此外,由于这些 java->native 编译器的结果不是一个有效的 java 程序,我不确定“java 编译器”是否真的适合。嗯。
  • 有这样的编译器,不知道是不是都过时了,还有在硬件上运行字节码的芯片,也已经过时了。时尚已经结束,语言仍然保留着巨大的利基市场,但 Sun 探索了每条途径。
  • @iMohammad:Java 并不是唯一一种使用编译模型生成字节码并使用虚拟机的语言。所有 .NET 语言都使用非常相似的技术。相反,C++ 并不是唯一直接编译为机器代码的语言。 FORTRAN 是另一个。 (呸!我刚刚和自己约会了吗?)
【解决方案2】:

C(和 C++)编译模型涉及两个方面。一是它的历史比 Java 更长,这意味着它适合功能非常低的编译器和机器。二是编译target,通常是低级机器码。

要针对低内存编译器环境,C 代码必须从上到下可读,不能回溯。这意味着您必须遵守严格的声明顺序。 (C++ 对类定义放宽了一点。)此外,每个源文件都必须可编译为独立的翻译单元,它不需要了解其他源文件的任何信息。

其次,因为 C 以低级机器代码为目标,这意味着每个翻译单元基本上都包含 no 元数据,这与 Java 类文件形成鲜明对比。这需要更严格的编码规则,其中每个翻译单元都必须提供必要的声明。编译器不能仅仅扫描所有其他文件以获得所需的信息;由用户提供。 (C++ 更严格地强制执行这一点,在 C 中,您可以通过忘记声明来避免令人讨厌的错误。)

请记住,C 程序必须在编译时完全编译和链接,因此此时必须已经有很多信息可用。 Java 程序可以在运行时加载类,并且 Java 执行通常在运行时执行更多“合适”的操作(本质上是强制转换,而不是 C 中的静态链接)。 Java 更复杂的运行时环境允许更灵活和模块化的编译模型。

【讨论】:

  • 我认为这个回复增加了有价值的输入。
  • "请记住,C 程序必须在编译时完全编译和链接" 并非绝对正确,因为我们也可以在 C/C++ 中在运行时进行加载。此外,clang 表明您可以解决一些提到的限制,但假设“经典编译”确实意味着传统方法可能会省事。仍然+1,很好的总结-如果我们想在这里涵盖所有可能的内容,那将占用太多空间。
  • @Voo:好吧,当然可以编写具有不同编译模型的完全不同的编译器。也就是说,C 标准确实规定了我描述的相当多的行为。我想说,运行时链接对于讨论并不重要,因为它与编译模型无关。 (例如,见this post。)
  • @Kerrek 很公平,这进入了一个相当深奥的领域,但我明白你的意思。
  • @Voo:另一种解释为什么动态链接不相关的方法:DL 是一个不透明的库提供的服务,您可以显式调用它。它不透明。唯一对编译模型重要的是编译器可以采用同一段源代码并生成运行程序的不同方式(例如编译时与加载时链接)。
【解决方案3】:

我会勇敢地比较表现。 ;)

Java 编译器javac 很少进行优化,更喜欢语法检查代码。它会进行所有必要的合理检查,以确保它可以在 JVM 上运行,并进行一些持续的评估,仅此而已。

大部分智能编译是由 JIT 完成的,它可以根据程序的使用方式执行动态复杂化。这允许它内联“虚拟”方法,例如,即使调用者和被调用者位于不同的库中。

C/C++ 编译器预先执行重要的静态分析。这意味着程序从一开始就几乎全速运行。 CPU 通过指令重新排序和分支预测执行一些动态优化。虽然 C/C++ 缺乏动态优化,但它通过使对系统的低级别访问变得更加更容易而受益。 (这在 Java 中通常不是不可能的,但在 C/C++ 中微不足道的低级操作在 Java 中可能是复杂而晦涩的)它还提供了更多方法来做同样的事情,让您为您的问题选择最佳解决方案。

当 Java 可能更快时。

  • 如果您的编程风格适合 Java,并且您只使用 Java 支持的那种功能,Java 可能会稍微快一些(由于动态编译),也就是说,您无论如何都不会充分利用 C/C++。
  • 如果您的代码包含大量死代码(可能只知道在运行时死了),Java 可以很好地消除这种情况。 (恕我直言,大量表明 Java 比 C++ 更快的微基准测试属于这种类型)
  • 您实施应用程序的时间和/或资源非常有限。 (在这种情况下,更高级别的语言可能会更好)即您没有时间优化代码,您需要编写安全的抽象代码。

当 C/C++ 可能更快时。

  • 如果您使用 C/C++ 提供的大部分功能。一些更高级的程序员倾向于做的事情。
  • 如果启动时间很重要。
  • 如果您需要在算法或数据结构方面发挥创造力。
  • 如果您可以利用低级硬件功能,例如直接访问设备。

【讨论】:

    【解决方案4】:

    简而言之,“经典”编译(这是材料提供的一个临时术语,因为它们没有真正的词),基本上是针对真实设备(在我们的例子中是具有物理处理器的机器)进行编译)。相反,Java 编译为针对虚拟设备的代码,虚拟设备是安装在机器上的软件。虚拟设备是改变并以真机为目标的设备。

    这样你的硬件就被抽象了。这就是 Java 可以在“任何”机器上工作的原因。

    【讨论】:

    • 我不确定这些答案中的任何一个是否真的解决了编译 model——我们都在谈论编译器发出的内容。当然,按模型,我们也指的是发射发生的过程,例如编译单元的差异?更不用说某个 Java 编译器可以根据需要发出机器码。
    • @Doug 我确定他收集这个问题的材料(通过提到“经典与 Java”完全与机器与虚拟代码有关。你指出的事实Java 编译器可以发出机器码,这几乎验证了我的观点。
    【解决方案5】:

    基本上,有两种魔法。 机器魔法只有特定的巫师才能理解。 JVM 字节码 魔法被一种特殊的向导所理解,您必须雇用该向导才能使机器向导能够施放使您的计算机执行操作的咒语。 C 和 C++ 编译器通常发出 machine 类型,而 Java 编译器发出 JVM 字节码

    【讨论】:

    • -1 针对白痴。你通过引用一些人不知道的东西无意中瞄准了较少的人。
    • 我试图为每个人的星期一早上增添一些乐趣。对不起,我冒犯了你。我会用你的回答来弥补我对 SeriousBusiness(tm) 犯下的罪行
    • 没有冒犯我。它只是不需要靠近顶部的任何地方。我希望我可以在不影响您的代表的情况下否决投票。现在正确答案有 6 票
    • 编辑,如果允许,我会撤消。
    【解决方案6】:

    C/C++ 在执行前被编译。

    Java 在执行时被编译。

    当然,这两种语言都没有规定某种编译方式。

    【讨论】:

    • 我相信“Java 在执行时被编译”的说法并不完全正确。 Java不能一直编译到平台吗?
    • @JohnDibling 见第三句。我认为语言不应该与编译方法联系在一起,所以我概括了答案。
    【解决方案7】:

    没有区别。两者都将人类理解的源代码转换为某些机器可以理解的机器代码。在 Java 的情况下,它针对的是虚拟机,即程序而不是硅片。

    当然,没有什么可以阻止硅片理解 JVM 字节码(在这种情况下,您可以将其从“字节码”重命名为“机器码”)。相反,没有什么可以阻止编译器将 C/C++ 代码转换为 JVM 字节码。

    两者都有一个运行时,都需要你告诉它你打算使用运行时的哪些部分。

    我真的认为你打算问一个不同的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-10
      • 1970-01-01
      • 1970-01-01
      • 2020-03-13
      • 2013-05-16
      • 2019-03-08
      相关资源
      最近更新 更多