using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;namespace stringAddress
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct A
{
public string str;
}
unsafe class Program
{
static void Main(string[] args)
{
A a = new A();
a.str = "Hello World!"; Console.WriteLine(Marshal.SizeOf(a));
fixed (char* p = a.str)
{
Console.WriteLine((int)p);//--------------------PrintOne
} IntPtr ptr = IntPtr.Zero;
ptr = Marshal.AllocHGlobal(Marshal.SizeOf(a));
Marshal.StructureToPtr(a, ptr, true);
int* pI = (int*)ptr;
Console.WriteLine((int)(*pI));//--------------------PrintTwo
}
}
}我认为PrintOne和PrintTwo的值应该是一样的,都是"Hello World!"在托管堆中的地址,也就是str这个引用的值,可是结果却不同,望高手赐教!
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;namespace stringAddress
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct A
{
public string str;
}
unsafe class Program
{
static void Main(string[] args)
{
A a = new A();
a.str = "Hello World!"; Console.WriteLine(Marshal.SizeOf(a));
fixed (char* p = a.str)
{
Console.WriteLine((int)p);//--------------------PrintOne
} IntPtr ptr = IntPtr.Zero;
ptr = Marshal.AllocHGlobal(Marshal.SizeOf(a));
Marshal.StructureToPtr(a, ptr, true);
int* pI = (int*)ptr;
Console.WriteLine((int)(*pI));//--------------------PrintTwo
}
}
}我认为PrintOne和PrintTwo的值应该是一样的,都是"Hello World!"在托管堆中的地址,也就是str这个引用的值,可是结果却不同,望高手赐教!
虽然今天是愚人节,可是小弟从不愚人
Console.WriteLine((int)(*pI));//--------------------PrintTwo
后我再加点代码
char* pI = (char*)ptr;
console.writeline(*pI);
打印出来的也该是'H',可是实际打印出来的是 ?
又作何解释
把Marshal.StructureToPtr(a, ptr, true);
下面的两行代码换成这三行
int* pCc = (int*)ptr;
byte* c = (byte*)(*pCc);
Console.WriteLine((char)c[0]);
DirectRay 兄虽然没说出具体原因,但是至少给了我提示,再加上msdn中这句解释假设 ptr 指向非托管内存块。此内存块的布局由相应的托管类 structure 描述。StructureToPtr 将字段值从结构封送到指针。假设 ptr 块包含引用字段,该字段指向当前包含“abc”的字符串缓冲区。假设托管端上相应的字段是包含“vwxyz”的字符串。如果不另行通知它,StructureToPtr 将分配一个新的非托管缓冲区来保存“vwxyz”,并将它挂钩到 ptr 块。这将丢弃旧缓冲区“abc”使之漂移而不将其释放回非托管堆。最后,您将得到一个孤立的缓冲区,它表示在代码中存在内存泄漏。如果将 fDeleteOld 参数设置为真,则 StructureToPtr 在继续为“vwxyz”分配新缓冲区之前释放保存“abc”的缓冲区。就像明白了。给dr兄30分吧,希望不要介意 ^_^
其实MSDN解释的时候有个问题没有说清楚,就是C#里面很多东西都是存的地址。你生成了几个不同的string,所以,地址必然和结构不一致。