问题描述
有一个关于 阅读 C 的有见地的问题来自字节数组的 C# 中的/C++ 数据结构,但我无法让代码适用于我的大端(网络字节顺序)字节集合.(请注意,我真正的结构不止一个字段.)有没有办法将字节编组为结构的大端版本,然后提取框架字节序中的值(主机的字节序),通常是小端)?
There is an insightful question about reading a C/C++ data structure in C# from a byte array, but I cannot get the code to work for my collection of big-endian (network byte order) bytes. ( Note that my real struct has more than just one field.) Is there a way to marshal the bytes into a big-endian version of the structure and then pull out the values in the endianness of the framework (that of the host, which is usually little-endian)?
(请注意,反转字节数组将不起作用 - 每个值的字节必须反转,这不会为您提供与反转所有字节相同的集合.)
(Note, reversing the array of bytes will not work - each value's bytes must be reversed, which does not give you the same collection as reversing all of the bytes.)
这应该总结我在寻找什么(LE=LittleEndian,BE=BigEndian):
This should summarize what I'm looking for (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
{
???
}
其他有用的链接:
结构字节和字节序问题
更多关于字节和字节序(字节顺序)
使用 C# 更高效地读取二进制文件
不安全并从文件中读取
Mono 对该问题的贡献
掌握 C# 结构
推荐答案
正如我在@weismat 的回答中提到的,有一种简单的方法可以实现大端结构.它涉及双重反转:将原始字节完全反转,然后结构本身是原始(大端)数据格式的反转.
As alluded to in my comment on @weismat's answer, there is an easy way to achieve big-endian structuring. It involves a double-reversal: the original bytes are reversed entirely, then the struct itself is the reversal of the original (big-endian) data format.
Main
中的fooLe
和fooBe
对于所有字段将具有相同的值.(通常情况下,little-endian 结构和字节当然不会出现,但这清楚地表明了字节顺序之间的关系.)
The fooLe
and fooBe
in Main
will have the same values for all fields. (Normally, the little-endian struct and bytes wouldn't be present, of course, but this clearly shows the relationship between the byte orders.)
注意:请参阅更新代码,包括如何从结构中取回字节.
NOTE: See updated code including how to get bytes back out of the struct.
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
};
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
};
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;
}
这篇关于将大端字节集合编组到结构中以提取值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!