为什么管理字符串做printf的工作? [英] Why does printf work with managed Strings?
问题描述
我们正在通过挖掘一些非常旧的C ++ / CLI的code(旧语法.NET测试版),并都感到有点惊讶地看到这样的内容:
we are currently digging through some really old C++/CLI-Code (Old Syntax .NET Beta) and were a bit surprised to see something like this:
System::String ^source("Test-String");
printf("%s", source);
程序正确输出
The program correctly outputs
Test-String
我们想知道,为什么它可以通过托管字符串源的printf
- 更重要的是:为什么它的工作原理的?我不希望它是一些方便,功能由编译器,因为下面不工作:
We are wondering, why is it possible to pass the managed string source to printf
- and more importantly: Why does it work? I don't expect it to be some convenience-feature by the compiler because the following doesn't work:
System::String ^source("Test-String");
char pDest[256];
strcpy(pDest, source);
这产生了(不知何故预期)编译错误,指出系统::字符串^
无法转换为为const char *
。所以,我唯一真正的解释是,通过一个管理引用的va_list超过了所有编译器检查和技巧本土code到使用指针到托管堆中。由于系统::字符串
重新presented类似于字符
-array在内存中,的printf
可能工作。或者编译器转换为 pin_ptr
并传递,为的printf
。
This produces a (somehow expected) compiling error saying that System::String^
can't be converted to const char*
. So my only real explaination is that passing a managed reference to a va_list surpasses all compiler-checks and tricks the native code into using a pointer into the managed heap. Since System::String
is represented similar to a char
-Array in memory, printf
may work. Or the compiler converts to a pin_ptr
and passes that to printf
.
我不希望它自动元帅字符串^
到的char *
,因为这会导致没有任何参照实际的内存地址的坏内存泄漏。
I don't expect it to automatically marshal the String^
to char*
, because that would result in a bad memory leak without any reference to the actual memory address.
我们知道,这不是一个很好的解决方案,并在后来的Visual Studio-版本中引入的各种编组方法提供了一种更好的方法,但是这将是非常有趣的,了解什么是真正发生在这里。
We know that this isn't a good solution and the various marshalling methods introduced by the later Visual Studio-Versions provide a way better approach but it would be very interesting to understand what is actually happening here.
谢谢!
推荐答案
我相信这是因为编译器把它变成这个IL:
I believe it is because the compiler is turning it into this 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
,所以运行时是有点偷偷摸摸的在整理给你。你仍然在管理运行时和运行时将提供marhsalling因为当它需要的服务。
Which ends up as a pinvoke call to printf
, so the runtime is being a little sneaky by marshalling it for you. You are still in a managed runtime, and the runtime will provide marhsalling as a service when it's needed.
一些注意事项:
看来, CLR!GenericPInvokeCalliHelper
是这样做的提升在x86 .NET 4工作站CLR。
It seems that clr!GenericPInvokeCalliHelper
is doing this lifting on the x86 .NET 4 Workstation CLR.
以下不能正常工作
这是因为是直的C ++。它没有机会,因为它并不需要经过编组
That's because that is straight C++. It has no chance to go through marshalling because it isn't needed.
这篇关于为什么管理字符串做printf的工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!