简体   繁体   English

使用 bigEndian 将结构转换为字节数组

[英]Struct to byte array with bigEndian

Hi Im trying to find way how to convert struct to byte array (from little endian to big)嗨,我正在尝试找到将结构转换为字节数组(从小端到大端)的方法

I know how to convert struct to byte array but question is how to do it with conversion from little to big endian.我知道如何将结构转换为字节数组,但问题是如何通过从小端到大端的转换来做到这一点。

Data in struct is in luttle endian but data of byte array must be in BigEndian because of Bus Standard...结构中的数据是 luttle endian 但字节数组的数据必须是 BigEndian 因为总线标准......

I found more solution of conversion but not to much with endian conversion too.我发现了更多的转换解决方案,但字节序转换的解决方案也不多。

For struct to byteArray Im using:对于 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;
    }

A solution is to declare the struct with fields in reverse order:一种解决方案是以相反的顺序声明具有字段的结构:

[StructLayout(LayoutKind.Sequential, Pack = 4)] // optional packing
public struct MyStruct
{
    public Byte   B1;
    public Int16  A3;
    public UInt16 A2;
    public UInt32 A1;
}

Or specify the layout to be in reverse order:或者将布局指定为相反的顺序:

[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;
}

Then when converted to a byte array, to reverse the byte array:然后当转换为字节数组时,要反转字节数组:

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;
}

Thus the fields will be in the correct position and the endianness will be inverted.因此,这些字段将位于正确的位置,并且字节顺序将被反转。

Have you tried your first approach with an struct that contains an array?您是否尝试过使用包含数组的结构的第一种方法? That won't work because Marshal.SizeOf will return the size of the pointer to the int-array (x86=4, x64=8) and not the length of the int-array...这不起作用,因为Marshal.SizeOf将返回指向 int-array (x86=4, x64=8) 的指针的大小,而不是 int-array 的长度......

I don't know for sure how an array will be written to a byte array in C. But I assume the following:我不确定如何将数组写入 C 中的字节数组。但我假设以下内容:

new int[] { 10,11,12 }
should result in a 12 byte long byte-array: four bytes for the length and three times four bytes for each array-item.应该产生一个 12 字节长的字节数组:长度为 4 个字节,每个数组项为 4 个字节的三倍。 So on a little-endian-system it would look like所以在小端系统上它看起来像
new byte[] { 3,0,0,0, 10,0,0,0, 11,0,0,0, 12,0,0,0 } . new byte[] { 3,0,0,0, 10,0,0,0, 11,0,0,0, 12,0,0,0 }
I also don't know how this have to look on a big-endian system, but I assume that only the byte-blocks have to be reversed and not the order.我也不知道这在大端系统上的外观如何,但我认为只有字节块必须反转,而不是顺序。 So fo a big endian system it could like所以对于一个大端系统来说,它可能会喜欢
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,10, 0,0,0,11, 0,0,0,12 }
or, if the order of the items also has to be reversed, it might look like或者,如果项目的顺序也必须颠倒,它可能看起来像
new byte[] { 0,0,0,3, 0,0,0,12, 0,0,0,11, 0,0,0,10 } . 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();
}

Also keep in mind that the MSDN page of .GetFields() contains the following notice:另请记住, .GetFields()MSDN页面包含以下通知:

The GetFields method does not return fields in a particular order, such as alphabetical or declaration order. GetFields 方法不返回特定顺序的字段,例如字母顺序或声明顺序。 Your code must not depend on the order in which fields are returned, because that order varies.您的代码不得依赖于返回字段的顺序,因为该顺序会有所不同。

Thats the reason why you should use an attribute to define the order and not to rely on the coincidence that the the framework version you're using returns them in declaration order.这就是为什么您应该使用属性来定义顺序而不是依赖于您使用的框架版本以声明顺序返回它们的巧合的原因。

// 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();
        }
    }
}

execution执行

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM