C#和Java这样的语言如何避免像C/C++那样的独立编译?

7

为了我的编程语言课,我正在撰写一篇关于语言设计历史上一些重要人物论文的研究论文。其中一篇由CAR Hoare所写的论文引起了我的注意,因为它反对独立编译技术,而在C甚至变得流行之前,这种技术就已被用于C和后来的C++。

既然这主要是为了优化加快编译时间,那么Java和C#有什么特点使它们能够避免依赖于独立编译?是编译器技术还是语言本身的元素有助于实现这一点?还有其他编译语言在它们之前使用过这些技术吗?

6个回答

6
简短回答:Java和C#并没有避免单独编译,它们充分利用了单独编译。
它们的区别在于,在编写可重用库时,它们不需要程序员编写一对单独的头文件/实现文件。用户只需编写类的定义一次,编译器就会从该单个定义中提取等同于“头文件”的信息,并将其包含在输出文件中作为“类型元数据”。因此,输出文件(Java中的一个装满.class文件的.jar文件或.NET语言中的.dll程序集)是二进制文件和头文件的组合。
然后,当另一个类被编译并依赖于第一个类时,它可以查看元数据,而无需找到单独的包含文件。
它们的目标是虚拟机而不是特定的芯片架构,但这是一个单独的问题;它们可以将x86机器代码放入二进制文件中,并将类似头文件的元数据放在同一个文件中(实际上,这是.NET中的一个选项,尽管很少使用)。
在C ++编译器中,通常尝试通过使用“预编译头文件”来加速编译。.NET .dll .class 文件中的元数据非常像预编译头文件-已经解析和索引,可以进行快速查找。
总之,在这些现代语言中,有一种模块化方法,并且具有完美组织和手动优化的C ++模块化构建系统的特点-非常棒,ASFAC ++ B

4

在我看来,最大的一个因素是Java和.NET都使用中间语言。这意味着编译后的单元(jar/assembly)包含了许多有关类型、方法等的表达式元数据作为前提条件,这意味着已经方便地布置好以供参考检查。运行时会进行检查,以防你想耍花招 ;-p

这与支撑COM的MIDL并没有太大区别,尽管TLB通常是一个单独的实体。

如果我误解了您的意思,请告诉我...


相信你已经正确地理解了我的意思。我基本上是指C/C++中每个源文件都是其自己的编译单元的概念。但在C#或Java中似乎不完全如此。 - Jason Baker

3
您可以将Java .class文件视为C/C++中的预编译头文件。 .class文件本质上是C/C++链接器所需的中间形式,以及标头中包含的所有信息(Java没有单独的标头)。
在另一篇文章中说: “我基本上是指C/C++中每个源文件都是其自己的单独编译单元的想法。这在C#或Java中似乎并不是那么明显。”
在Java中(我不知道C#是否相同),每个源文件都是其自己的单独编译单元。我不确定您为什么认为它不是...也许我们对编译单元有不同的定义?

2
需要一些语言支持(否则,C/C++编译器也可以做到)
特别地,需要编译器生成自包含模块,这些模块公开元数据,其他模块可以引用它们来调用其中的函数。
.NET程序集就是一个简单的例子。项目中的所有文件都编译在一起,生成一个dll文件。.NET可以查询该dll以确定其包含的类型,以便其他程序集可以调用其中定义的函数。
为了使用它,语言必须允许引用其他模块。
在C++中,什么定义了模块的边界?语言规定编译器只考虑当前编译单元(.cpp文件+包含的头文件)中的数据。没有机制可以指定“我想调用模块Bar中的函数Foo,即使我在编译时没有原型或任何东西”。您唯一可以用于在文件之间共享类型信息的机制是#include。
有一个提案将模块系统添加到C++中,但它不会出现在C++0x中。据我所知,计划是在0x发布后考虑将其纳入TR1。
(值得一提的是,C/C++中的#include系统最初是因为它可以加快编译速度而被使用的。在70年代,它允许编译器在一个简单的线性扫描中处理代码。它不必构建语法树或其他“高级”功能。今天,情况已经发生了逆转,它已成为一个巨大的瓶颈,无论是在可用性还是编译速度方面。)

C语言的设计更多地基于确保编译在内存受限的机器上是可行的,而不是试图使其快速。如今,几乎没有系统的整个源代码无法轻松适应典型桌面计算机的RAM,但C语言是在一个大型机器的RAM不到今天日常工作站的1/16,000时代设计的。开发环境必须在构建速度和最大实用构建大小之间做出严格的权衡。 - supercat

2

C/C++生成的目标文件仅供链接器读取,而不是编译器。


1
关于其他语言:如果我没记错,Turbo Pascal 有“单元”的概念,你可以在不需要任何源代码的情况下使用它们。我认为关键是要创建与编译代码一起的元数据,然后由编译器来找出模块的接口(即函数签名、类布局等)。
C/C++ 的一个问题是宏预处理器,它可以完全改变包含/导入模块的含义、语法等。这对于类似 Java 的模块系统来说会非常困难(如果不是不可能的话)。

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