gpt4 book ai didi

.net - 将大端字节集合编码到结构中以提取值

转载 作者:行者123 更新时间:2023-12-02 11:50:24 25 4
gpt4 key购买 nike

有一个关于 reading a C/C++ data structure in C# from a byte array 的富有洞察力的问题,但我无法让代码适用于我的大端(网络字节顺序)字节集合。 (编辑:请注意,我的真实结构不止一个字段。)有没有一种方法可以将字节编码到结构的大端版本中,然后以框架的字节顺序(主机的字节顺序)提取值,通常是小尾数)?

(请注意,反转字节数组不起作用 - 每个值的字节都必须反转,这不会为您提供与反转所有字节相同的集合。)

这应该总结了我正在寻找的内容(LE=LittleEndian,BE=BigEndian):

void Main()
{
var leBytes = new byte[] {1, 0, 2, 0};
var beBytes = new byte[] {0, 1, 0, 2};
Foo fooLe = ByteArrayToStructure<Foo>(leBytes);
Foo fooBe = ByteArrayToStructureBigEndian<Foo>(beBytes);
Assert.AreEqual(fooLe, fooBe);
}

[StructLayout(LayoutKind.Explicit, Size=4)]
public struct Foo {
[FieldOffset(0)]
public ushort firstUshort;
[FieldOffset(2)]
public ushort secondUshort;
}

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) where T: struct
{
???
}

其他有用的链接:

Byte of a struct and onto endian concerns

A little more on bytes and endianness (byte order)

Read binary files more efficiently using C#

Unsafe and reading from files

Mono's contribution to the issue

Mastering C# structs

最佳答案

这是交换字节顺序的另一种解决方案。

它是根据 Adam Robinsons 解决方案进行调整的:https://stackoverflow.com/a/2624377/1254743

它甚至能够处理嵌套结构。

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

}

关于.net - 将大端字节集合编码到结构中以提取值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2480116/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com