为什么IntPtr.ToString()返回的是内存地址而不是字符串?

3
请参考以下代码片段。
private void MyMethod() 
{
    IntPtr myVar = Marshal.AllocHGlobal(1024);
    string hello = "Hello World";
    Marshal.Copy(hello.ToCharArray(), 0, myVar, hello.Length);

    //I don't see Hello World here. Instead, I see a memory address. WHY???
    Debug.Print(myVar.ToString()); 
    Marshal.FreeHGlobal(myVar);
}

我错在哪里了? 我期望看到“Hello World”,但我没有看到。
3个回答

4
当然,你会看到一个内存地址。你刚刚将字符串复制到非托管内存中,并打印了IntPtr对象的字符串表示形式,这是一个内存地址。指针不告诉.NET框架期望什么类型 - 它是非托管数据。
如果你想从非托管内存中读取数据,你需要将该数据转换回托管字符串。

2
一个 IntPtr 是一个未指定类型的指针。编译器和运行时都不知道它背后是什么。因此,在 IntPtr 上实现 ToString() 的过程必须执行某些操作,无论指针引用了什么,都具有意义。因此,它返回 IntPtr 变量的数值。

事实上,方法文档已经很清楚地说明了这一点:

将当前 IntPtr 对象的数值转换为其等效字符串表示形式。

就其价值而言,你的代码复制到非托管内存的方式充其量是危险的。它不会复制空终止符。更重要的是,这段代码是不必要的,因为框架已经提供了一个现成的方法,Marshal.StringToHGlobalUni

IntPtr ptr = Marshal.StringToHGlobalUni("Hello World");

如果您想获取字符串后面的文本,则可以调用 Marshal.PtrToStringUni。显然,只有在修复缺失的空终止符时才实用。

Marshal.StringToHGlobalUni 的文档中可以得知:"此方法会复制嵌入的空字符,并包含一个终止空字符。" 那么当你说 "显然,只有在修复缺失的空终止符时才是实用的" 时,你的意思是什么? - Kris Vandermotten

0
应该使用Marshal.StringToHGlobalUni或Marshal.StringToHGlobalAuto()。
在这里,您可以看到您的字符串。

Debug.Print(Marshal.PtrToStringAuto(myVar));


由于缺少空终止符,这将失败。无论如何都应该使用PtrToStringUni。文本始终为UTF-16格式,即使在Win9x上也是如此。 - David Heffernan
显然应该使用Marshal.StringToHGlobalUni。 FYI:Marshal.PtrToStringAuto只是PtrToStringUni的花哨名称。 - Abdullah Saleem
同意。但你在回答中没有提到这一点。 - David Heffernan
我的错。已编辑原始内容。 - Abdullah Saleem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接