在.NET语言中,我对于机器码和本地码感到困惑。
它们有什么区别?它们是相同的吗?
在.NET语言中,我对于机器码和本地码感到困惑。
它们有什么区别?它们是相同的吗?
这些术语确实有点混淆,因为它们有时候被不一致地使用。
机器码: 这是最明确定义的术语。它是使用字节码指令编写的代码,这些指令是您的处理器(实际执行工作的物理金属部件)理解并直接执行的。在执行其他代码之前,必须将所有其他代码转换或转化为机器码。
本地代码: 该术语有时在指代机器码(参见上文)时使用。但是,有时也用于指代非托管代码(参见下文)。
非托管代码和托管代码: 非托管代码是指使用C或C++等编程语言编写的代码,直接编译成机器码。它与托管代码形成对比,后者是使用C#、VB.NET、Java或类似语言编写的,在虚拟环境(如.NET或JavaVM)中执行,该环境在软件中“模拟”处理器。主要区别在于,托管代码通过采用垃圾回收和保持对象不透明的引用来为您“管理”资源(大多数是内存分配)。 非托管代码是需要手动分配和释放内存的代码,有时会导致内存泄漏(当您忘记释放时)和有时会导致分段错误(当您释放得太早时)。非托管还通常意味着没有运行时检查常见错误,例如空指针引用或数组边界溢出。
严格来说,大多数动态类型语言-例如Perl、Python、PHP和Ruby-也是托管代码。但是,它们不常被描述为此类代码,这表明托管代码实际上是一种营销术语,适用于真正大型、严肃、商业化的编程环境(.NET和Java)。
汇编代码: 该术语通常是指那些想要编写字节码的源代码。 汇编器 是一个将这个源代码转换为真正的字节码的程序。它不属于 编译器 ,因为转换是1对1的。然而,该术语在使用什么样的字节码方面是模棱两可的:它可以是托管或非托管的。如果是非托管的,则生成的字节码就是 机器码。如果是托管的,则产生的字节码是由类似 .NET 这样的虚拟环境在幕后使用的字节码。托管代码(例如 C#、Java)被编译成这种特殊的字节码语言,在 .NET 的情况下称为 公共中间语言 (CIL) ,在 Java 中称为 Java 字节码。通常情况下,普通程序员很少需要访问或直接使用这段代码,但是当人们这样做时,他们经常把它称为 汇编代码,因为他们使用 汇编器 将其转换为字节码。
static void Main(string[] args) {
Console.WriteLine("Hello world");
00000000 55 push ebp ; save stack frame pointer
00000001 8B EC mov ebp,esp ; setup current frame
00000003 E8 30 BE 03 6F call 6F03BE38 ; Console.Out property getter
00000008 8B C8 mov ecx,eax ; setup "this"
0000000a 8B 15 88 20 BD 02 mov edx,dword ptr ds:[02BD2088h] ; arg = "Hello world"
00000010 8B 01 mov eax,dword ptr [ecx] ; TextWriter reference
00000012 FF 90 D8 00 00 00 call dword ptr [eax+000000D8h] ; TextWriter.WriteLine()
00000018 5D pop ebp ; restore stack frame pointer
}
00000019 C3 ret ; done, return
int _tmain(int argc, _TCHAR* argv[])
{
00401010 55 push ebp
00401011 8B EC mov ebp,esp
printf("Hello world");
00401013 68 6C 6C 45 00 push offset ___xt_z+128h (456C6Ch)
00401018 E8 13 00 00 00 call printf (401030h)
0040101D 83 C4 04 add esp,4
return 0;
00401020 33 C0 xor eax,eax
}
00401022 5D pop ebp
00401023 C3 ret
我没有对其进行注释,主要是因为它与C#程序生成的机器代码非常相似。printf()函数调用与Console.WriteLine()调用有很大不同,但其他部分几乎相同。请注意,调试器现在正在生成实际的机器代码地址,并且对符号更加智能。这是生成调试信息之后生成机器代码的副作用,就像不受管辖的编译器经常做的一样。我还应该提到,我关闭了一些机器代码优化选项,使机器代码看起来类似。 C / C ++编译器有更多时间可用于优化代码,结果通常难以解释。而且非常难调试。
关键点是由JIT编译器从托管语言生成的机器代码和由本地代码编译器生成的机器代码之间几乎没有区别。这就是C#语言可以与本地代码编译器竞争的主要原因。它们之间唯一的真正区别是支持函数调用。其中许多实现在CLR中。这主要涉及垃圾收集器。
本地代码和机器码是同一件事情 - CPU执行的实际字节。
汇编代码有两个意思:一个是将机器码翻译成更易读的形式(使用类似于“JMP”这样的短词汇来翻译指令的字节,该指令会“跳转”到代码中的另一个位置)。另一个是IL字节码(由C#或VB等编译器生成的指令字节,最终将被翻译为机器码,但目前还没有),它存在于DLL或EXE中。