2

I've found questions such as this one, which have come close to solving my dilemma. However, I've yet to find a clean approach to solving this issue in a generic manner.

I have a project that has a lot of structs that will be used for binary data transmission. This data needs to be Big Endian and, of course, most .Net architecture is Little Endian. This means that when I convert my structs to bytes, the byte order for my values are reversed.

Is there a fairly straight-forward approach to either forcing my structs to contain data in Big Endian format, or is there a way to generically write these structs to byte arrays (and byte arrays to structs) that output Big Endian data?

Here is some sample code for what I've already done.

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct StructType_1
{
    short shortVal;
    ulong ulongVal;
    int intVal;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct StructType_2
{
    long longVal_1;
    long longVal_2;
    long longVal;
    int intVal;
}

...

public static class StructHelper
{
    //How can I change the following methods so that the struct data 
    //is converted to and from BigEndian data?
    public static byte[] StructToByteArray<T>(T structVal) where T : struct
    {
        int size = Marshal.SizeOf(structVal);
        byte[] arr = new byte[size];
        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(structVal, ptr, true);
        Marshal.Copy(ptr, arr, 0, size);
        Marshal.FreeHGlobal(ptr);
        return arr;
    }

    public static T StructFromByteArray<T>(byte[] bytes) where T : struct
    {
        int sz = Marshal.SizeOf(typeof(T));
        IntPtr buff = Marshal.AllocHGlobal(sz);
        Marshal.Copy(bytes, 0, buff, sz);
        T ret = (T)Marshal.PtrToStructure(buff, typeof(T));
        Marshal.FreeHGlobal(buff);
        return ret;
    }
}
Community
  • 1
  • 1
RLH
  • 15,230
  • 22
  • 98
  • 182

2 Answers2

1

If you don't mind reading and writing each field to a stream (which may have performance implications) you could use Jon Skeet's EndianBinaryWriter: https://stackoverflow.com/a/1540269/106159

The code would look something like this:

public unsafe struct StructType_2
{
    long longVal_1;
    long longVal_2;
    long longVal;
    int intVal;
}

using (MemoryStream memory = new MemoryStream())
{
    using (EndianBinaryWriter writer = new EndianBinaryWriter(EndianBitConverter.Big, stream))
    {
        writer.Write(longVal_1);
        writer.Write(longVal_2);
        writer.Write(longVal);
        writer.Write(intVal);
    }

    byte[] buffer = memory.ToArray();

    // Use buffer
}

You would use the EndianBinaryReader for data going in the opposite direction.

This does of course have two fairly large drawbacks:

  • It's fiddly writing code to read and write each field.
  • It may be too slow to do it this way, depending on performance requirements.

Also have a look at this answers to this similar question: Marshalling a big-endian byte collection into a struct in order to pull out values

Community
  • 1
  • 1
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • I might be able to use the solution in the linked answer (toward the bottom of your response.) This will almost certainly have a significant negative impact on performance. Possibly, I might be able to integrate an architecture check. I could always expect LE data (since 95-98% of my systems will probably be on LE machines.) If it is a BE system, then I could call the conversion routines. It will suck for the BE architecture users but it will work. I'm OK with creating a caste system within my user base if it's necessary to keep this application fast for overwhelming majority of users. – RLH Sep 12 '14 at 13:14
0

Given the example on the BitConverter that shows converting a uint, I would suspect not.

RLH
  • 15,230
  • 22
  • 98
  • 182
Richard
  • 106,783
  • 21
  • 203
  • 265