[英]Struct to byte array with bigEndian
嗨,我正在尝试找到将结构转换为字节数组(从小端到大端)的方法
我知道如何将结构转换为字节数组,但问题是如何通过从小端到大端的转换来做到这一点。
结构中的数据是 luttle endian 但字节数组的数据必须是 BigEndian 因为总线标准......
我发现了更多的转换解决方案,但字节序转换的解决方案也不多。
对于 byteArray Im 使用的结构:
public byte[] getBytes<T>(T str)
{
int size = Marshal.SizeOf(str);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}
public struct MyStruct
{
public UInt32 A1;
public UInt16 A2;
public Int16 A3;
public Byte B1;
}
一种解决方案是以相反的顺序声明具有字段的结构:
[StructLayout(LayoutKind.Sequential, Pack = 4)] // optional packing
public struct MyStruct
{
public Byte B1;
public Int16 A3;
public UInt16 A2;
public UInt32 A1;
}
或者将布局指定为相反的顺序:
[StructLayout(LayoutKind.Explicit, Size = 9)] // optional packing
public struct MyStruct
{
[FieldOffset(5)]
public UInt32 A1;
[FieldOffset(3)]
public UInt16 A2;
[FieldOffset(1)]
public Int16 A3;
[FieldOffset(0)]
public Byte B1;
}
然后当转换为字节数组时,要反转字节数组:
public byte[] getBytes<T>(T str)
{
int size = Marshal.SizeOf(str);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
Array.Reverse(arr);
return arr;
}
因此,这些字段将位于正确的位置,并且字节顺序将被反转。
您是否尝试过使用包含数组的结构的第一种方法? 这不起作用,因为Marshal.SizeOf
将返回指向 int-array (x86=4, x64=8) 的指针的大小,而不是 int-array 的长度......
我不确定如何将数组写入 C 中的字节数组。但我假设以下内容:
new int[] { 10,11,12 }
应该产生一个 12 字节长的字节数组:长度为 4 个字节,每个数组项为 4 个字节的三倍。 所以在小端系统上它看起来像
new byte[] { 3,0,0,0, 10,0,0,0, 11,0,0,0, 12,0,0,0 }
。
我也不知道这在大端系统上的外观如何,但我认为只有字节块必须反转,而不是顺序。 所以对于一个大端系统来说,它可能会喜欢
new byte[] { 0,0,0,3, 0,0,0,10, 0,0,0,11, 0,0,0,12 }
。
或者,如果项目的顺序也必须颠倒,它可能看起来像
new byte[] { 0,0,0,3, 0,0,0,12, 0,0,0,11, 0,0,0,10 }
。
public static byte[] StructToArray<T>(T obj)
{
var size = Marshal.SizeOf(obj);
var mem = new MemoryStream(size);
var fields = obj.GetType().GetFields();
var little = BitConverter.IsLittleEndian;
foreach(var field in fields)
{
var val = field.GetValue(obj);
var type = val.GetType();
if(type == typeof(int))
{
var raw = BitConverter.GetBytes((int)val);
if (little) raw = raw.Reverse().ToArray();
mem.Write(raw, 0, raw.Length);
}
else if(type == typeof(int[]))
{
var array = (int[])val;
var length = BitConverter.GetBytes(array.Length);
if (little) length = length.Reverse().ToArray();
var raw = array.Select(x => BitConverter.GetBytes(x)).ToList();
if (little) raw = raw.Select(x => x.Reverse().ToArray()).ToList();
// Write the length...
mem.Write(length, 0, length.Length);
// ...and the items in "normal" order
for (int i = 0; i < raw.Count; i++)
mem.Write(raw[i], 0, raw[i].Length);
}
}
return mem.ToArray();
}
另请记住, .GetFields()
的MSDN页面包含以下通知:
GetFields 方法不返回特定顺序的字段,例如字母顺序或声明顺序。 您的代码不得依赖于返回字段的顺序,因为该顺序会有所不同。
这就是为什么您应该使用属性来定义顺序而不是依赖于您使用的框架版本以声明顺序返回它们的巧合的原因。
// test case
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Test1
{
class Program
{
public static byte[] getBytes<T>(T str)
{
int size = Marshal.SizeOf(str);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
Array.Reverse(arr);
return arr;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)] // optional packing
public struct MyStruct
{
public UInt16 B;
public UInt32 A;
}
static void Main(string[] args)
{
MyStruct x = new MyStruct();
x.A = 0xa1a2a3a4;
x.B = 0xb1b2;
byte[] arr = getBytes<MyStruct>(x);
MyStruct y = new MyStruct();
y.A = BitConverter.ToUInt32(arr, 0);
y.B = BitConverter.ToUInt16(arr, sizeof(UInt32));
Console.ReadLine();
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.