这个问题存在很多互相矛盾的信息。有人说C#是编译型语言(因为在运行时,它被编译成中间代码(IL),然后再编译成本地代码),而另一些人则称其为解释型语言,因为它需要.NET才能运行。英文维基百科表示:
许多解释型语言首先被编译成某种虚拟机器码,然后在运行时被解释或编译成本地代码。
所以我非常困惑。有没有人能够清楚地解释这个问题呢?
这个问题存在很多互相矛盾的信息。有人说C#是编译型语言(因为在运行时,它被编译成中间代码(IL),然后再编译成本地代码),而另一些人则称其为解释型语言,因为它需要.NET才能运行。英文维基百科表示:
许多解释型语言首先被编译成某种虚拟机器码,然后在运行时被解释或编译成本地代码。
所以我非常困惑。有没有人能够清楚地解释这个问题呢?
C#被C#编译器编译成IL。
然后,当需要时,这个IL会被即时编译(JIT)成主机机器的本地组合语言。虽然可以编写一个.NET运行时来解释IL,但我仍然认为C#是一种编译语言。
一种纯粹的编译语言具有一些优点,例如速度通常较快,工作集大小也较小。一种纯粹的解释语言也具有一些优点,例如不需要显式编译阶段的灵活性,可以在原地编辑,而且通常更易于可移植性。
一种即时编译语言位于这种情况的中间地带。
这就是为什么我们可能会将即时编译语言视为编译或解释语言,具体取决于我们关心哪个指标,并对其中一个持支持或反对态度的原因之一。
C#也可以在第一次运行时进行编译,就像在ASP.NET中发生的那样,这使得它在这种情况下接近解释,尽管它仍然被编译为IL代码,然后在这种情况下被JIT编译。当然,在这种情况下,它几乎具有解释的所有优点(与经典ASP中使用的VBScript或JScript进行比较),以及大部分编译的优点。
严格地说,没有任何语言是即时编译的,解释的或编译的 qua语言。我们可以将C#NGen到本机代码(尽管如果它执行诸如动态加载程序集的操作,它仍将使用IL和JIT编译)。我们可以为C或C ++编写解释器(几个人已经这样做了)。但是在其最常见的用例中,C#被编译为IL代码,然后被JIT编译,这与解释或编译的经典定义并不完全相同。
语义和观点过多。
首先:C# 不是解释性语言;CLR 和 JVM 被视为"运行时"或"中间件",但同样的名称也适用于像 Perl 这样的东西。这在关注名称的人中间造成了很多混乱。
引用运行时的"解释器"一词通常意味着现有的代码解释一些非本地代码。有两个大范畴:解析读取原始源代码并采取逻辑动作;字节码执行首先将代码编译为非本地二进制表示,需要更少的 CPU 循环来解释。
Java 最初编译为字节码,然后通过解释器;现在,JVM 读取字节码并即时将其编译为本地代码。CIL 也是如此:CLR 使用即时编译到本机代码。
考虑运行源代码、运行字节码、编译为本机代码、即时编译、将源代码通过编译器运行到即时本机等所有组合的情况。语言是编译还是解释的语义变得毫无意义。
例如:许多解释性语言使用即时字节码编译。C# 编译为 CIL,JIT 编译为本机代码;相比之下,Perl 立即将脚本编译为字节码,然后通过解释器运行这个字节码。你只能在 CIL 字节码格式中运行 C# 组装;你只能在原始源代码格式中运行 Perl 脚本。
即时编译器还运行许多外部和内部的仪表记录。运行时跟踪各种函数的执行,然后调整代码布局以优化其特定执行流的分支和代码组织。这意味着 JIT 代码可以比本地编译的代码(例如通常是 C++ 的,或者像 C# 运行通过 IL2CPP)运行得更快,因为 JIT 调整其优化策略以代码运行时的实际执行情况为依据。
欢迎来到计算机编程的世界。我们决定让它变得非常复杂,然后给每件事都附上不具描述性的名称。目的是为了在没有实际意义的单词定义上创建火焰战争。
看这里:http://msdn.microsoft.com/library/z1zx9t92
C# 编写的源代码被编译为符合 CLI 规范的中间语言(IL)。
(...)
当 C# 程序执行时,程序集被加载到 CLR 中,CLR 可能会基于清单中的信息执行各种操作。然后,如果安全要求得到满足,CLR 将执行即时 (JIT) 编译将 IL 代码转换成本地机器指令。
首先,让我们了解解释和编译的定义。
"编译"(指代码时)意味着将代码从一种语言翻译成另一种语言。通常是从人类可读的源代码翻译为目标处理器可以处理的机器码。
"解释"(指代码时)也意味着将代码从一种语言翻译成另一种语言。但这次通常用于将人类可读的源代码转换为中间代码,由虚拟机接收并将其解释为机器码。
只是为了明确
源代码 -> 编译器 -> 机器码
源代码 -> 编译器 -> 字节码 -> 解释器 -> 机器码
大多数语言(如果不是全部),需要一个解释器来将它们的脚本翻译成机器代码,以使CPU能够理解和执行它!
每种语言处理翻译过程的方式都不同!
例如,“AutoIt”就可以描述为一种100%解释语言!
为什么?
因为“AutoIt”解释器在执行其脚本时必须始终存在!请参见以下示例:
Loop, 1000
Any-Code
我相信这是一个相当古老的话题。
从我的角度来看,解释性代码将通过解释器逐行翻译和执行。例如JavaScript,它是一种解释性代码,当一行JavaScript遇到错误时,脚本会停止。
而编译性代码则会经过编译器,一次性将所有代码转换为另一种形式的代码,而不需要先执行它。执行在另一个上下文中进行。