Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 将big-endian字节集合编组到结构中以提取值_.net_Interop_Mono_Legacy_Endianness - Fatal编程技术网

.net 将big-endian字节集合编组到结构中以提取值

.net 将big-endian字节集合编组到结构中以提取值,.net,interop,mono,legacy,endianness,.net,Interop,Mono,Legacy,Endianness,关于这个问题有一个很有见地的问题,但我无法让代码用于我收集的big-endian(网络字节顺序)字节。(编辑:请注意,我的真实结构不止一个字段。)有没有办法将字节封送到结构的大端版本中,然后从框架的端(主机的端,通常是小端)中取出值 (注意,反转字节数组将不起作用-每个值的字节必须反转,这与反转所有字节的集合不同。) 这应该是我想要的东西的总结(LE=LittleEndian,BE=BigEndian): void Main() { var leBytes=新字节[]{1,0,2,0}; var

关于这个问题有一个很有见地的问题,但我无法让代码用于我收集的big-endian(网络字节顺序)字节。(编辑:请注意,我的真实结构不止一个字段。)有没有办法将字节封送到结构的大端版本中,然后从框架的端(主机的端,通常是小端)中取出值

(注意,反转字节数组将不起作用-每个值的字节必须反转,这与反转所有字节的集合不同。)

这应该是我想要的东西的总结(LE=LittleEndian,BE=BigEndian):

void Main()
{
var leBytes=新字节[]{1,0,2,0};
var beBytes=新字节[]{0,1,0,2};
Foo-傻瓜=字节数组结构(leBytes);
Foo fooBe=byteArrayStructureBigendian(字节);
主张平等(愚蠢、愚蠢);
}
[StructLayout(LayoutKind.Explicit,Size=4)]
公共结构Foo{
[字段偏移量(0)]
公共卫生服务优先卫生服务;
[现场偏移(2)]
公共卫生服务第二卫生服务;
}
T ByteArrayToStructure(字节[]字节),其中T:struct
{
GCHandle=GCHandle.Alloc(字节,GCHandleType.pinted);
T stuff=(T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),typeof(T));
handle.Free();
归还物品;
}
T byteArrayStructureBigendian(字节[]字节),其中T:struct
{
???
}
其他有用的链接:


你试过MiscUtil吗?它有一个名为
EndianBitConverter
的实用程序类,用于在大字节数组和小字节数组之间进行转换


从我的观点来看,在转换字节数组之前,您只需要添加一个数组。Reverse()。

我同意@weismat,并且相信没有解决方案

您在示例中展示的是,您可以像访问任何其他结构一样访问原始字节缓冲区,而无需对其进行任何更改,无需复制或移动数据,也无需执行任何操作。只是固定它以避免它因为GC而四处移动

这基本上是在C中通过使用包含目标结构和相同大小的字节数组的联合类型实现的

好的一面是它真的很有效

这有几个缺点,主要的一个是您只能通过这种方式访问本机顺序的数据(无论是LE还是be)。因此,您的ByteArrayToStructure并不是真正的LE,这只是因为下面的处理器是LE。如果您在另一个目标上编译了相同的程序,那么它的工作方式正好相反,并且相信您的字节数组是正确的

其他缺点是,您必须非常谨慎地进行数据对齐,注意可能的填充等。当然,如果不移动字节数组中的数据,就无法将字节顺序从LE更改为BETE(如果您有一个仅16位整数的数组,如示例中所示,这只是每两个字节交换一次)


我碰巧遇到了类似的问题,由于前面的缺点,我决定不使用这个解决方案,并选择将输入结构隐藏在访问器后面,以隐藏对下面字节数组的访问。它可能没有那么优雅,但它很简单,也避免了以任何方式复制缓冲区或移动数据。

似乎必须有一个更优雅的解决方案,但这至少可以让您继续:

    static T ByteArrayToStructureBigEndian<T>(byte[] bytes) where T : struct
    {
        GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
        handle.Free();
        System.Type t = stuff.GetType();
        FieldInfo[] fieldInfo = t.GetFields();
        foreach (FieldInfo fi in fieldInfo)
        {                 
            if (fi.FieldType == typeof(System.Int16))
            {
                // TODO
            }
            else if (fi.FieldType == typeof(System.Int32))
            {
                // TODO
            }
            else if (fi.FieldType == typeof(System.Int64))
            {
                // TODO
            }
            else if (fi.FieldType == typeof(System.UInt16))
            {
                UInt16 i16 = (UInt16)fi.GetValue(stuff);
                byte[] b16 = BitConverter.GetBytes(i16);
                byte[] b16r = b16.Reverse().ToArray();
                fi.SetValueDirect(__makeref(stuff), BitConverter.ToUInt16(b16r, 0);
            }
            else if (fi.FieldType == typeof(System.UInt32))
            {
                // TODO
            }
            else if (fi.FieldType == typeof(System.UInt64))
            {
                // TODO
            }
        }
        return stuff;
    }
静态T byteArrayStructureBigendian(字节[]字节),其中T:struct
{
GCHandle=GCHandle.Alloc(字节,GCHandleType.pinted);
T stuff=(T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),typeof(T));
handle.Free();
System.Type t=stuff.GetType();
FieldInfo[]FieldInfo=t.GetFields();
foreach(FieldInfo中的FieldInfo fi)
{                 
if(fi.FieldType==typeof(System.Int16))
{
//待办事项
}
else if(fi.FieldType==typeof(System.Int32))
{
//待办事项
}
else if(fi.FieldType==typeof(System.Int64))
{
//待办事项
}
else if(fi.FieldType==typeof(System.UInt16))
{
UInt16 i16=(UInt16)fi.GetValue(stuff);
字节[]b16=位转换器.GetBytes(i16);
字节[]b16r=b16.Reverse().ToArray();
fi.SetValueDirect(uu makeref(stuff),BitConverter.ToUInt16(b16r,0);
}
else if(fi.FieldType==typeof(System.UInt32))
{
//待办事项
}
else if(fi.FieldType==typeof(System.UInt64))
{
//待办事项
}
}
归还物品;
}

传统的解决方案是使用ntohl()和ntohs()

上述操作适用于任何具有BSD套接字的平台,无论它是big-endian、little-endian还是像VAX这样非常奇怪的东西。相反的操作是使用hton*()完成的


在big-endian平台上,函数通常没有ops,因此应该是零成本的。

我最终找到了一种不涉及反射的方法,并且大部分是用户友好的。它使用Mono的类(),不幸的是,在这一点上它有相当多的缺陷。(例如,float和double似乎无法正常工作,字符串解析被破坏,等等)

诀窍是将字节解包并重新打包为big-endian,这需要一个字符串来描述字节数组中的类型(参见最后一种方法)。此外,字节对齐也很棘手:结构中有四个字节,而不是一个,因为封送似乎依赖于四字节对齐(我仍然不太理解这一部分)。(编辑:我发现向中添加
Pack=1
通常可以解决字节对齐问题。)

注意,此示例代码用于LINQPad—转储扩展方法j
    static T ByteArrayToStructureBigEndian<T>(byte[] bytes) where T : struct
    {
        GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
        handle.Free();
        System.Type t = stuff.GetType();
        FieldInfo[] fieldInfo = t.GetFields();
        foreach (FieldInfo fi in fieldInfo)
        {                 
            if (fi.FieldType == typeof(System.Int16))
            {
                // TODO
            }
            else if (fi.FieldType == typeof(System.Int32))
            {
                // TODO
            }
            else if (fi.FieldType == typeof(System.Int64))
            {
                // TODO
            }
            else if (fi.FieldType == typeof(System.UInt16))
            {
                UInt16 i16 = (UInt16)fi.GetValue(stuff);
                byte[] b16 = BitConverter.GetBytes(i16);
                byte[] b16r = b16.Reverse().ToArray();
                fi.SetValueDirect(__makeref(stuff), BitConverter.ToUInt16(b16r, 0);
            }
            else if (fi.FieldType == typeof(System.UInt32))
            {
                // TODO
            }
            else if (fi.FieldType == typeof(System.UInt64))
            {
                // TODO
            }
        }
        return stuff;
    }
typedef struct {
  long foo;
  short bar, baz;
  char xyzzy;
} Data;

Data d;
memcpy(&d, buffer, sizeof(Data));

d.foo = ntohl(d.foo);
d.bar = ntohs(d.bar);
d.baz = ntohs(d.baz);
// don't need to change d.xyxxy
public void Main()
{
    var beBytes = new byte[] {
        0x80, 
        0x80, 
        0x80, 
        0x80, 
        0x80,0, 
        0x80,0, 
        0x80,0,0,0, 
        0x80,0,0,0,
        0x80,0,0,0,0,0,0,0, 
        0x80,0,0,0,0,0,0,0, 
//      0,0,0x80,0x3F, // float of 1
//      0,0,0,0,0,0,0xF0,0x3F, // double of 1
        0x54,0x65,0x73,0x74,0x69,0x6E,0x67,0,0,0 // Testing\0\0\0
    };
    var leBytes = new byte[] {
        0x80, 
        0x80, 
        0x80, 
        0x80, 
        0,0x80,
        0,0x80, 
        0,0,0,0x80,
        0,0,0,0x80, 
        0,0,0,0,0,0,0,0x80, 
        0,0,0,0,0,0,0,0x80, 
//      0,0,0x80,0x3F, // float of 1
//      0,0,0,0,0,0,0xF0,0x3F, // double of 1
        0x54,0x65,0x73,0x74,0x69,0x6E,0x67,0,0,0 // Testing\0\0\0
    };
    Foo fooLe = ByteArrayToStructure<Foo>(leBytes).Dump("LE");
    Foo fooBe = ByteArrayToStructureBigEndian<Foo>(beBytes, 
        "bbbbsSiIlL"
//      + "fd" // float, then double
        +"9bb").Dump("BE");
    Assert.AreEqual(fooLe, fooBe);
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Foo  {
    public byte b1;
    public byte b2;
    public byte b3;
    public byte b4;
    public short s;
    public ushort S;
    public int i;
    public uint I;
    public long l;
    public ulong L;
//  public float f;
//  public double d;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string MyString;
}

T ByteArrayToStructure<T>(byte[] bytes) where T: struct 
{
    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),typeof(T));
    handle.Free();
    return stuff;
}

T ByteArrayToStructureBigEndian<T>(byte[] bytes, string description) where T: struct 
{
    byte[] buffer = bytes;
    IList unpacked = DataConverter.Unpack("^"+description, buffer, 0).Dump("unpacked");
    buffer = DataConverter.PackEnumerable("!"+description, unpacked).Dump("packed");
    return ByteArrayToStructure<T>(buffer);
}
public void Main()
{
    var beBytes = new byte[] {
        0x80, 
        0x80,0, 
        0x80,0, 
        0x80,0,0,0, 
        0x80,0,0,0,
        0x80,0,0,0,0,0,0,0, 
        0x80,0,0,0,0,0,0,0, 
        0x3F,0X80,0,0, // float of 1 (see http://en.wikipedia.org/wiki/Endianness#Floating-point_and_endianness)
        0x3F,0xF0,0,0,0,0,0,0, // double of 1
        0,0,0,0x67,0x6E,0x69,0x74,0x73,0x65,0x54 // Testing\0\0\0
    };
    var leBytes = new byte[] {
        0x80, 
        0,0x80,
        0,0x80, 
        0,0,0,0x80,
        0,0,0,0x80, 
        0,0,0,0,0,0,0,0x80, 
        0,0,0,0,0,0,0,0x80, 
        0,0,0x80,0x3F, // float of 1
        0,0,0,0,0,0,0xF0,0x3F, // double of 1
        0x54,0x65,0x73,0x74,0x69,0x6E,0x67,0,0,0 // Testing\0\0\0
    };
    Foo fooLe = ByteArrayToStructure<Foo>(leBytes).Dump("LE");
    FooReversed fooBe = ByteArrayToStructure<FooReversed>(beBytes.Reverse().ToArray()).Dump("BE");  
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Foo  {
    public byte b1;
    public short s;
    public ushort S;
    public int i;
    public uint I;
    public long l;
    public ulong L;
    public float f;
    public double d;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string MyString;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct FooReversed  {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string MyString;
    public double d;
    public float f;
    public ulong L;
    public long l;
    public uint I;
    public int i;
    public ushort S;
    public short s;
    public byte b1;
}

T ByteArrayToStructure<T>(byte[] bytes) where T: struct 
{
    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),typeof(T));
    handle.Free();
    return stuff;
}
public static class FooTest
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct Foo2
    {
        public byte b1;
        public short s;
        public ushort S;
        public int i;
        public uint I;
        public long l;
        public ulong L;
        public float f;
        public double d;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
        public string MyString;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct Foo
    {
        public byte b1;
        public short s;
        public ushort S;
        public int i;
        public uint I;
        public long l;
        public ulong L;
        public float f;
        public double d;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
        public string MyString;
        public Foo2 foo2;
    }

    public static void test()
    {
        Foo2 sample2 = new Foo2()
        {
            b1 = 0x01,
            s = 0x0203,
            S = 0x0405,
            i = 0x06070809,
            I = 0x0a0b0c0d,
            l = 0xe0f101112131415,
            L = 0x161718191a1b1c,
            f = 1.234f,
            d = 4.56789,
            MyString = @"123456789", // null terminated => only 9 characters!
        };

        Foo sample = new Foo()
        {
            b1 = 0x01,
            s = 0x0203,
            S = 0x0405,
            i = 0x06070809,
            I = 0x0a0b0c0d,
            l = 0xe0f101112131415,
            L = 0x161718191a1b1c,
            f = 1.234f,
            d = 4.56789,
            MyString = @"123456789", // null terminated => only 9 characters!
            foo2 = sample2,
        };

        var bytes_LE = Dummy.StructToBytes(sample, Endianness.LittleEndian);
        var restoredLEAsLE = Dummy.BytesToStruct<Foo>(bytes_LE, Endianness.LittleEndian);
        var restoredLEAsBE = Dummy.BytesToStruct<Foo>(bytes_LE, Endianness.BigEndian);

        var bytes_BE = Dummy.StructToBytes(sample, Endianness.BigEndian);
        var restoredBEAsLE = Dummy.BytesToStruct<Foo>(bytes_BE, Endianness.LittleEndian);
        var restoredBEAsBE = Dummy.BytesToStruct<Foo>(bytes_BE, Endianness.BigEndian);

        Debug.Assert(sample.Equals(restoredLEAsLE));
        Debug.Assert(sample.Equals(restoredBEAsBE));
        Debug.Assert(restoredBEAsLE.Equals(restoredLEAsBE));
    }

    public enum Endianness
    {
        BigEndian,
        LittleEndian
    }

    private static void MaybeAdjustEndianness(Type type, byte[] data, Endianness endianness, int startOffset = 0)
    {
        if ((BitConverter.IsLittleEndian) == (endianness == Endianness.LittleEndian))
        {
            // nothing to change => return
            return;
        }

        foreach (var field in type.GetFields())
        {
            var fieldType = field.FieldType;
            if (field.IsStatic)
                // don't process static fields
                continue;

            if (fieldType == typeof(string)) 
                // don't swap bytes for strings
                continue;

            var offset = Marshal.OffsetOf(type, field.Name).ToInt32();

            // handle enums
            if (fieldType.IsEnum)
                fieldType = Enum.GetUnderlyingType(fieldType);

            // check for sub-fields to recurse if necessary
            var subFields = fieldType.GetFields().Where(subField => subField.IsStatic == false).ToArray();

            var effectiveOffset = startOffset + offset;

            if (subFields.Length == 0)
            {
                Array.Reverse(data, effectiveOffset, Marshal.SizeOf(fieldType));
            }
            else
            {
                // recurse
                MaybeAdjustEndianness(fieldType, data, endianness, effectiveOffset);
            }
        }
    }

    internal static T BytesToStruct<T>(byte[] rawData, Endianness endianness) where T : struct
    {
        T result = default(T);

        MaybeAdjustEndianness(typeof(T), rawData, endianness);

        GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);

        try
        {
            IntPtr rawDataPtr = handle.AddrOfPinnedObject();
            result = (T)Marshal.PtrToStructure(rawDataPtr, typeof(T));
        }
        finally
        {
            handle.Free();
        }

        return result;
    }

    internal static byte[] StructToBytes<T>(T data, Endianness endianness) where T : struct
    {
        byte[] rawData = new byte[Marshal.SizeOf(data)];
        GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
        try
        {
            IntPtr rawDataPtr = handle.AddrOfPinnedObject();
            Marshal.StructureToPtr(data, rawDataPtr, false);
        }
        finally
        {
            handle.Free();
        }

        MaybeAdjustEndianness(typeof(T), rawData, endianness);

        return rawData;
    }

}