将 sbyte[] 固定为字符串 C#
Fixed sbyte[] to string C#
我正在尝试使用 StrucLayout
和 FieldOffset
从内存中获取字符串
但我很难理解 byte
的工作原理。
这是我的 ATM 代码:
[StructLayout(LayoutKind.Explicit)]
public unsafe struct InfoDetails
{
[FieldOffset(0x14)]
public fixed sbyte Name[50];
public string getName
{
get
{
fixed (sbyte* namePtr = Name)
{
return new string(namePtr);
}
}
}
}
此代码 returns
:T
。预期结果是 TEZ
.
关于我为什么做错的任何建议?
谢谢
您的字符串编码似乎有问题。考虑以下测试代码:
unsafe
{
InfoDetails d;
var encoding = Encoding.Unicode;
var stringBytes = encoding.GetBytes("TEZ");
for(int i=0; i<stringBytes.Length; i++) d.Name[i] = (sbyte)stringBytes[i];
Console.WriteLine(d.getName);
}
您确实会得到 "T",但是如果您将编码更改为 Encoding.ASCII
,您会得到预期的 "TEZ"。
解决方法:需要事先知道信息的编码方式,并据此生成字符串。看起来是 Unicode,所以先试试这个:
fixed (sbyte* namePtr = Name)
{
return new string(namePtr, 0, 50, Encoding.Unicode);
}
感谢大家的回答,他们帮助我找到了可行的解决方案。我真的不知道这是不是最好的:
[StructLayout(LayoutKind.Explicit)]
public unsafe struct InfoDetails
{
[FieldOffset(0x14)]
public fixed byte Name[50];
public string test
{
get
{
List<byte> clearBytes = new List<byte>();
fixed (byte* namePtr = Name)
{
for (int i = 0; i < 50; i++)
{
if (namePtr[i] == 0x0 && namePtr[i + 1] == 0x0)
{
break;
}
clearBytes.Add(namePtr[i]);
}
if (clearBytes.Count() % 2 != 0)
{
clearBytes.Add(0x00);
}
return Encoding.Unicode.GetString(clearBytes.ToArray());
}
}
}
}
非常感谢!
您可以将签名更改为:
[FieldOffset(0x14)]
public fixed char Name[25];
public string getName
{
get
{
fixed (char* namePtr = Name)
{
return new string(namePtr);
}
}
}
请注意我是如何将 sbyte
更改为 char
并将缓冲区大小减半的(因为 sizeof(char)
== 2)
或者您甚至可以更简单地向 char*
添加一个转换:
fixed (sbyte* namePtr = Name)
{
return new string((char*)namePtr);
}
不改变任何其他内容。
我正在尝试使用 StrucLayout
和 FieldOffset
但我很难理解 byte
的工作原理。
这是我的 ATM 代码:
[StructLayout(LayoutKind.Explicit)]
public unsafe struct InfoDetails
{
[FieldOffset(0x14)]
public fixed sbyte Name[50];
public string getName
{
get
{
fixed (sbyte* namePtr = Name)
{
return new string(namePtr);
}
}
}
}
此代码 returns
:T
。预期结果是 TEZ
.
关于我为什么做错的任何建议? 谢谢
您的字符串编码似乎有问题。考虑以下测试代码:
unsafe
{
InfoDetails d;
var encoding = Encoding.Unicode;
var stringBytes = encoding.GetBytes("TEZ");
for(int i=0; i<stringBytes.Length; i++) d.Name[i] = (sbyte)stringBytes[i];
Console.WriteLine(d.getName);
}
您确实会得到 "T",但是如果您将编码更改为 Encoding.ASCII
,您会得到预期的 "TEZ"。
解决方法:需要事先知道信息的编码方式,并据此生成字符串。看起来是 Unicode,所以先试试这个:
fixed (sbyte* namePtr = Name)
{
return new string(namePtr, 0, 50, Encoding.Unicode);
}
感谢大家的回答,他们帮助我找到了可行的解决方案。我真的不知道这是不是最好的:
[StructLayout(LayoutKind.Explicit)]
public unsafe struct InfoDetails
{
[FieldOffset(0x14)]
public fixed byte Name[50];
public string test
{
get
{
List<byte> clearBytes = new List<byte>();
fixed (byte* namePtr = Name)
{
for (int i = 0; i < 50; i++)
{
if (namePtr[i] == 0x0 && namePtr[i + 1] == 0x0)
{
break;
}
clearBytes.Add(namePtr[i]);
}
if (clearBytes.Count() % 2 != 0)
{
clearBytes.Add(0x00);
}
return Encoding.Unicode.GetString(clearBytes.ToArray());
}
}
}
}
非常感谢!
您可以将签名更改为:
[FieldOffset(0x14)]
public fixed char Name[25];
public string getName
{
get
{
fixed (char* namePtr = Name)
{
return new string(namePtr);
}
}
}
请注意我是如何将 sbyte
更改为 char
并将缓冲区大小减半的(因为 sizeof(char)
== 2)
或者您甚至可以更简单地向 char*
添加一个转换:
fixed (sbyte* namePtr = Name)
{
return new string((char*)namePtr);
}
不改变任何其他内容。