将托管字符串编组为 char 指针 C#

Wil*_*iam 4 .net c# pointers unmanaged

我正在使用 C# 中的 Marshal 类,对此操作的结果有点困惑:

\n\n
string someVal = "Hello There";\nIntPtr ptS = Marshal.StringToHGlobalAnsi(someVal);\nchar* ptsPt = (char*)ptS.ToPointer();\n
Run Code Online (Sandbox Code Playgroud)\n\n

在立即窗口中查看 ptsPt[0] 后,它包含以下值:\\'\xe6\x95\x88\'

\n\n

我猜测这与将托管字符视为 8 位值的方法有关StringToHGlobalAnsi,但当它们实际上是 16 位时。但我不太明白为什么会发生这种情况。

\n\n

我知道我可以通过将其更改为 来解决这个问题StringToHGlobalUni。但我不明白这是为什么!

\n\n

干杯

\n

Rom*_*kov 5

这是因为在 C# 中,char是 16 位宽的类型。将字符串StringToHGlobalAnsi 转换为 ANSI,即每个字符 1 个字节。然后查看ptsPt[0],它被解释为包含前两个 ANSI 字符。

\n\n

这是原始字符串在内存中的样子:

\n\n
00 48 00 65 00 6C 00 6C 00 6F 00 20 ...\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是因为C#字符串是以UTF-16存储的,而上面的“Hello There”就是UTF-16。

\n\n

调用后StringToHGlobalAnsi,会分配一块新的内存,其中包含以下字节:

\n\n
48 65 6C 6C 6F 20 ...\n
Run Code Online (Sandbox Code Playgroud)\n\n

Marshal.FreeHGlobal(顺便说一句,这意味着您应该在完成后释放它)。

\n\n

然后,当您得到 achar*时,第一个char指向包含 bytes 48 65,由于小字节序,它实际上意味着0x6548,它代表字符 \xe6\x95\x88。

\n