6

我们目前正在研究一些非常古老的 C++/CLI 代码(Old Syntax .NET Beta),看到这样的东西有点惊讶:

System::String ^source("Test-String");
printf("%s", source);

程序正确输出

Test-String

我们想知道,为什么可以将托管字符串源传递给printf- 更重要的是:它为什么有效?我不希望它成为编译器的一些便利功能,因为以下内容不起作用:

System::String ^source("Test-String");
char pDest[256];
strcpy(pDest, source);

这会产生一个(以某种方式预期的)编译错误,指出System::String^无法转换为const char*. 所以我唯一真正的解释是,将托管引用传递给 va_list 会超越所有编译器检查,并欺骗本机代码使用指向托管堆的指针。由于在内存System::String中表示类似于char-Array,因此printf可能会起作用。或者编译器转换为 apin_ptr并将其传递给printf.

我不希望它自动编组String^to char*,因为这会导致严重的内存泄漏,而没有任何对实际内存地址的引用。

我们知道这不是一个好的解决方案,后来的 Visual Studio 版本引入的各种编组方法提供了一种更好的方法,但了解这里实际发生的事情会非常有趣。

谢谢!

4

1 回答 1

4

我相信这是因为编译器正在把它变成这个 IL:

call vararg int32 modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) printf(int8 modopt([mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte) modopt([mscorlib]System.Runtime.CompilerServices.IsConst)*, ..., string)

最终作为对 的 pinvoke 调用printf,因此运行时为您编组它有点偷偷摸摸。您仍处于托管运行时中,并且运行时将在需要时将编组作为服务提供。


一些注意事项:

似乎这clr!GenericPInvokeCalliHelper是在 x86 .NET 4 Workstation CLR 上进行的。

以下不起作用

那是因为那是直接的 C++。它没有机会通过编组,因为它不是必需的。

于 2012-08-06T15:51:54.837 回答