C++ 时如何进行编组?代码是从 C++/CLI 调用的吗?

发布于 2024-09-14 11:43:12 字数 301 浏览 13 评论 0原文

根据这个问题,有可能使用 C++/CLI 无缝组合托管和非托管代码。我不太明白 - 托管和非托管之间不应该进行编组吗?

例如,我有编译为本机 C++ .dll 并已发布标头的 InnerLibrary,以及从 InnerLibrary 调用代码的 C++/CLI OuterLibrary。会有编组吗?谁将实施它以及成本有多大?

According to this question it's possible to seamlessly combine managed and unmanaged code using C++/CLI. I don't quite get it - shouldn't there be marshalling between managed and unmanaged anyway?

For example, I have InnerLibrary that is compiled as a native C++ .dll with a header published and C++/CLI OuterLibrary that calls code from InnerLibrary. Will there be marshalling? Who will implement it and how costly will it be?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

勿挽旧人 2024-09-21 11:43:12

嗯,这是 C++/CLI 编译器内置的一项功能,称为 C++ Interop。您可能认为其中涉及的黑魔法要少得多。 JIT 编译器生成的机器代码与 C++ 编译器生成的机器代码完全相同。所有 .NET 值类型在 C++ 中都有直接等效项,因此无需转换。它不会自动处理引用类型,您必须自己处理。通常是 pin_ptr<>。

它实际上所做的只是注入一些代码来处理从托管堆栈帧到非托管堆栈帧的转换。该代码在堆栈上放置一个特殊的“cookie”,由垃圾收集器识别。这可以防止它误入非托管帧并将非托管指针错误地识别为对象引用。该代码没有太多内容,在发布版本中大约需要 5 纳秒。

Well, it's a feature that's built into the C++/CLI compiler, called C++ Interop. There's a lot less black magic involved that you might think. The JIT compiler generates the exact same kind of machine code as your C++ compiler generates. All of the .NET value types have a direct equivalent in C++ so no conversion is needed. It does not automatically handle reference types, you have to do that yourself. pin_ptr<>, typically.

All that it really does is inject a bit of code that handles the transition from a managed stack frame to an unmanaged stack frame. That code puts a special "cookie" on the stack, recognized by the garbage collector. Which prevents it from blundering into the unmanaged frames and mis-identify unmanaged pointers as object references. There's not much to that code, takes about 5 nanoseconds in the Release build, give or take.

云胡 2024-09-21 11:43:12

不必进行任何编组,因为 C++/CLI 能够发出直接进行调用的不安全代码。看一下 Reflector 中的一些 C++/CLI 代码——它看起来与 C# 非常不同。

这是 C# 无法做到的事情(至少,没有 unsafe 关键字和一些指针 hack),也是纯模式 C++/CLI 无法做到的事情(对于相同的情况)原因如 C#)。

.NET 不安全代码能够直接调用非托管函数;只是这种能力除了通过 C++/CLI 之外无法方便地使用。

There doesn't have to be any marshalling because C++/CLI is able to emit unsafe code that makes the call directly. Take a look at some C++/CLI code in Reflector -- it'll look very different from C#.

This is something that C# can't do (at least, not without the unsafe keyword and some pointer hacks), and it's also something that pure-mode C++/CLI can't do (for the same reason as C#).

.NET unsafe code is able to make direct calls to unmanaged functions; it's just that this ability isn't conveniently available except through C++/CLI.

呢古 2024-09-21 11:43:12

编组是将非托管数据或调用引入托管世界的过程。可以这么说,它只是两者之间的翻译。

使用 C++/CLI,您可以混合搭配。这意味着,如果您直接使用您的库、使用 *.h 文件并使用传统的 C++ 代码,它将是非托管的且无需封送。如果您使用 BCL 类或您自己的托管代码访问该数据,则您将手动添加封送处理层,但仅在需要时才添加。即,LPTSTR 需要转换为托管字符串才能用作一个字符串。使用 C++/CLI,您可以跳过此步骤并坚持使用传统的 C++ 代码,创建更快、更宽松的代码,但代价是不使用安全、经过检查的托管代码。

Marshaling is the process of bringing unmanaged data or calls to the managed world. It merely does — so to speak — a translation between the two.

Withing C++/CLI you can mix and match. That means, if you use your library directly, using the *.h file and using traditional C++ code, it will be unmanaged and without marshaling. If you access that data using BCL classes or your own managed code, you are adding the marshaling layer by hand, but only if needed. I.e., a LPTSTR will need to be translated into a managed string to be used as one. Using C++/CLI, you can skip this step and stick to traditional C++ code, creating faster and more lenient code, at the expense of not using safe, checked managed code.

巡山小妖精 2024-09-21 11:43:12

涉及编组,但您(即程序员)必须明确地执行它。

如果您的 C++CLI OuterLibrary 调用具有采用 System.String/System::String^ 的函数,则 C++ 类型系统要求您在之前执行类型转换将其传递给采用 const char* 的 InnerLibrary 函数。您必须自己进行转换 - 这就是编组。

Microsoft 发布了名为 C++ 支持库,它提供了有助于 C++ <-> 的函数C++CLI 交互。

There is marshalling invovled, but you (i.e. the programmer) must do it explicitly.

If your C++CLI OuterLibrary calls has a function that takes a System.String/System::String^, the C++ type system requires that you perform a type conversion before passing it to an InnerLibrary function that takes a const char*. You have to do the conversion yourself - which is the marshalling.

Microsoft ship something called the C++ Support Library, which provides functions that help with C++ <-> C++CLI interaction.

锦欢 2024-09-21 11:43:12

这取决于所涉及的数据类型。

诸如 intdouble 等内在类型(string 不符合条件)在本机代码和托管代码中具有相同的表示形式,不存在需要编组。内部类型的数组也以相同的方式布局(如果我们忽略元数据 .NET 存储,但它与数组内容是分开的)。

使用显式布局属性(其中所有成员都是内在类型)的值类型也是内存布局兼容的。

如果数据存储在托管堆上的对象内(对于所有数组都是如此),则可能需要固定。

另一方面,类类型必须来回转换/翻译。

It depends on the data types involved.

Intrinsic types such as int, double, and so on (string does not qualify) have the same representation in both native and managed code, no marshaling is required. Arrays of intrinsic types are laid out the same way as well (if we ignore the metadata .NET stores, but that's separate from the array content).

Value types using explicit layout attributes where all members are intrinsic types, are also memory layout-compatible.

Pinning may be required if the data is stored within an object on the managed heap (this is true for all arrays).

Class types, on the other hand, have to be converted/translated back and forth.

瀞厅☆埖开 2024-09-21 11:43:12

这里有两点:

1)托管/非托管代码转换:每次转换都有其固定成本。当 C++/CLI 代码在单个程序集中编译时,编译器会在可能的情况下尝试对所有代码进行托管,以最大程度地减少此类转​​换。当从 C++/CLI 代码调用外部非托管 Dll 时,这种优化是不可能的。因此,最好尽量减少这种转换,至少在时间关键的部分。请在此处查看有关此内容的更多信息:http://msdn.microsoft.com/en- us/magazine/dd315414.aspx,性能和互操作边界的位置

2) 参数编组。这取决于参数类型。有些参数不需要编组,例如 int 等简单类型。字符串应该编组。一些技巧(例如固定指针)可以防止简单类型数组编组。

There are two points here:

1) Managed/unmanaged code transition: every transition has its fixed cost. When C++/CLI code is compiled in a single assembly, compiler tries to make all the code managed, when it is possible, to minimize such transitions. When external unmanaged Dll is called from C++/CLI code, such optimization is impossible. Therefore, it is a good idea to minimize such transitions, at least in time-critical sections. See more about this here: http://msdn.microsoft.com/en-us/magazine/dd315414.aspx, Performance and the Location of Your Interop Boundary

2) Parameters marshalling. This depends on parameters type. Some parameters don't need to be marshalled, for example, simple types like int. Strings should be marshalled. Some tricks, like pinning pointers, allows to prevent simple type array marshalling.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文