C# 从指向固定字符数组的不安全字节指针获取字符串

C# 从指向固定字符数组的不安全字节指针获取字符串,c#,.net,string,pinvoke,unsafe,C#,.net,String,Pinvoke,Unsafe,我试图理解如何从以下结构中的不安全字节指针获取字符串。SDL_TEXTINPUTEVENT_TEXTSIZE为32 [StructLayout(LayoutKind.Sequential)] public unsafe struct SDL_TextInputEvent { public SDL_EventType type; public UInt32 timestamp; public UInt32 windowID; public fixed byte te

我试图理解如何从以下结构中的不安全字节指针获取字符串。SDL_TEXTINPUTEVENT_TEXTSIZE为32

[StructLayout(LayoutKind.Sequential)]
public unsafe struct SDL_TextInputEvent
{
    public SDL_EventType type;
    public UInt32 timestamp;
    public UInt32 windowID;
    public fixed byte text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
}
我试过:

byte[] rawBytes = new byte[SDL_TEXTINPUTEVENT_TEXT_SIZE];

unsafe
{
    Marshal.Copy((IntPtr)rawEvent.text.text, rawBytes, 0, SDL_TEXTINPUTEVENT_TEXT_SIZE);
}

string text = System.Text.Encoding.UTF8.GetString(rawBytes);
这种方法很有效,但是给了我一个字符串,除了实际输入的字符外,还有很多额外的字节。我应该解析字节数组并搜索以0结尾的字符以避免多余的字符吗

我完全误解了什么吗

作为参考,要封送到.NET运行时的原始C结构是:

typedef struct SDL_TextInputEvent
{
    Uint32 type;
    Uint32 timestamp;
    Uint32 windowID;
    char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
} SDL_TextInputEvent;

您确实需要找到空终止符。而且,
Marshal.Copy
不会这样做。如果文本是ANSI编码的,则可以使用
Marshal.PtrToStringAnsi
。但是UTF-8没有这样的功能。所以你需要在数组中迭代寻找一个零字节。当您遇到这样的问题时,您知道缓冲区的实际长度,并且可以修改现有代码以使用该长度,而不是最大可能长度。

我刚刚在.NET Core中遇到了同样的问题。幸运的是,由于.NETCore1.1/.NET标准2.1,有一种方法可以提供本机UTF-8字符串的转换

给定此结构:

[StructLayout(LayoutKind.Sequential,Pack=1)]
结构NativeType
{
公共整数;
公共不安全固定字节SomeString[16];
}
我们可以将二进制数据解码为ASCII和UTF-8,如下所示:

var byteArrayAscii=新字节[]{0x78、0x56、0x34、0x12、0x41、0x53、0x43、0x49、0x49、0x21、0x00、0x00、0x00、0x00、0x00、0x00、0x00、0x00、0x00、0x00、0x00、0x00};
var byteArrayUtf8=新字节[]{0xef,0xcd,0xab,0x89,0x45,0x6d,0x6f,0x6a,0x69,0x3a,0x20,0xf0,0x9f,0x91,0x8d,0x21,0x00,0x00,0x00,0x00,0x00};
使用var outputStream=File.OpenWrite(“output.txt”);
使用var outputWriter=newstreamWriter(outputStream);
不安全的
{
var decoded1=MemoryMarshal.Read(byteArrayAscii);
outputWriter.WriteLine($“编号1:{decoded1.SomeNumber:x8}”);
outputWriter.WriteLine($”字符串1:{Marshal.PtrToStringAnsi(新的IntPtr(decoded1.SomeString))});
}
不安全的
{
var decoded2=MemoryMarshal.Read(byteArrayUtf8);
outputWriter.WriteLine($“编号2:{decoded2.SomeNumber:x8}”);
outputWriter.WriteLine($”字符串2:{Marshal.PtrToStringUTF8(新的IntPtr(decoded2.SomeString))});
}
输出:

编号1:12345678 字符串1:ASCII! 2号:89abcdef
字符串2:Emoji:您是否需要在.NET结构中实际使用
byte
?我认为您应该能够保留
char
数组签名,然后在需要时将其转换为修剪过的字符串。@Ty char在C#中为16位,但在非托管代码中为B位,如果这是一种安慰,<代码> McSal.PrtoTrutUutf8/COD>存在于.NETCARE中,我刚使用它与OP完全相同的目的,同时将一个懒惰的FO教程转换成C++。