我在理解托管C++如何工作和编译时遇到了麻烦。

在.NET Framework中,您可以在C#/VB/F#/.. etc中开发代码。并且所有这些语言将被编译为与Java字节码相似的相同通用中间语言(CIL)。从理论上讲,CIL可以安装在任何平台上(Mono使其实用)。在Windows上,CLR将CIL编译为 native 代码Just-In-Time(JIT),一切运行顺利且运行良好。

现在,如何编译托管C++?它会编译为CIL代码并等待CLR使用JIT运行它吗?我认为不是,因为托管C++可以使用标准C++代码(未编译为CIL)。此外,它如何使用.NET程序集(CIL)?

我将不胜感激任何帮助。
谢谢

编辑:

我看过这个answer。它指出在C++/CLI中,托管代码被编译为MSIL,并且您可以选择将非托管代码编译为 native 代码或MSIL。因此,我现在了解如何调用.NET程序集。

无论如何,我仍然不了解如果将非托管代码编译为 native 代码,那么C++非托管代码如何与托管程序在同一程序集中运行。有任何想法吗?

最佳答案

这是一个很大的主题,包含非常严格的实现细节。很难解决所有这些问题,但是这个问题中存在一些误解。让我们解决这些问题,可能有助于进入下一阶段。



链接器不仅生成CIL,还生成混合模式的程序集。包含.NET元数据+ msil和 native 代码。实际上,就OS加载程序而言,可执行文件中的 native 代码是正常的。与本地C++编译器产生的类型没有区别。它像纯本地可执行镜像一样被加载和重定位。 .NET元数据+ msil是奇怪的东西。对于加载程序来说,它看起来就像是一块数据,根本不涉及数据。只有CLR可以。



不太准确,可以将 native C++代码编译为msil或机器代码。得到的结果取决于是使用/clr编译选项还是在功能级别有效的#pragma管理。例如,CIL与Java JVM中使用的字节码没有很好的比较。它功能更强大,可以支持任何符合C++ 03的 native C++代码。有时您故意这样做是为了利用反向拼写( native 代码调用托管代码)。有时这是偶然完成的,太多的 native C++代码被编译为msil。抖动产生的机器代码不是最佳的(它在时间限制下进行优化),并且不以任何方式进行管理。它是不可验证的,不会得到垃圾回收者的爱。

对于CIL而言,最好的心理形象是在前端(解析器)和后端(代码生成器和优化器)之间的任何 native C++编译器中使用的中间表示形式。通常是看不见的实现细节,但是当您使用使用LLVM的C++编译器时(就像Clang一样),该细节会变得更加明显。 .NET即时编译器在运行时会执行LLVM在编译时会执行的操作。

大多数程序员的心态是,托管代码调用 native 代码时(或相反),将抛出巨大的模式切换。那根本不准确。您可能想看看this post,它显示了C++编译器的后端产生的机器代码与抖动之间的区别。关键是它几乎相同,这是确保托管代码与 native 代码竞争的一项基本功能。帮助说明托管代码调用 native 代码(或相反)的方式不是那么特别。

另一个误解是托管代码会自动变得更安全。并非完全正确,像C#这样的语言使您可以像使用C++一样使用指针进行聚会并在堆栈上随意涂写,并且可以像这样轻松地破坏内存。它只是进行了更好的分区,它迫使您使用unsafe关键字对其进行明确说明。在C++/CLI上没有这样的约束,任何事情都会发生。

托管代码和 native 代码之间的本质区别是抖动在编译msil时生成的数据结构。您没有从 native 编译器获得的额外数据。该数据是垃圾收集器所必需的,它告诉它如何找到对象根。有关this post中的数据的更多信息。必须遵从该数据并允许GC完成其工作,这使得托管代码在运行时速度稍慢。

09-11 17:34