为什么printf与托管字符串一起使用?

时间:2012-08-06 15:37:23

标签: .net visual-studio-2010 c++-cli marshalling printf

我们正在深入研究一些非常古老的C ++ / CLI代码(旧语法.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 - 数组,因此printf可能有效。或者编译器转换为pin_ptr并将其传递给printf

我不希望它自动封送String^char*,因为这会导致内存泄漏,而不会引用实际的内存地址。

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

谢谢!

1 个答案:

答案 0 :(得分: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)

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


一些注意事项:

似乎clr!GenericPInvokeCalliHelper正在x86 .NET 4 Workstation CLR上进行此操作。

  

以下不起作用

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