0

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...

I found more solution of conversion but not to much with endian conversion too.

For struct to byteArray Im using:

    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;
    }
4
  • If this is only about raw-types, I would do the conversion manually: Iterate the fields via reflection (you might need an aditional attribute to keep the order of the fields), create the byte-array and then convert them field by field. If I remember correctly, Jon Skeets miscutils jonskeet.uk/csharp/miscutil contains a BitConverter class where you can specify the endian'es - or you do the conversion yourself. Commented Nov 25, 2017 at 11:04
  • To do the conversion yourself, you could use the .NET BitConverter, ensure that you're on a little endian system, call the .GetBytes() method and then reverse the order of the result array. Commented Nov 25, 2017 at 11:07
  • UInt16 input = (UInt16)0xabdc; UInt16 output = (UInt16)(((input << 8) & 0xFF00) | ((input >> 8) & 0xFF)); Commented Nov 25, 2017 at 12:52
  • Does this answer your question? How to get little endian data from big endian in c# using bitConverter.ToInt32 method? Commented Jul 6, 2022 at 13:53

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

I believe this solves the problem. Why would this not work?
Note the ARRAY.REVERSE and that the STRUCT is now reversed. Optionally packing can be explicit.
Just ran it. works fine. See the test case. Can a Professional Code Licking critic be “completely wrong”?
I was wrong. I hadn't read your reasoning, maybe because you hadn't written it.
0

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...

I don't know for sure how an array will be written to a byte array in C. But I assume the following:

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

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:

The GetFields method does not return fields in a particular order, such as alphabetical or declaration order. 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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.