Marshal 中 space 末尾的数据对齐
Alignment of data on the end side of space in Marshal
我有以下结构:
[StructLayout(LayoutKind.Sequential)]
public struct mystructure
{
public Byte fieldA;
public Byte fieldB;
public UInt16 fieldC;
public UInt32 fieldD;
}
然后,填充数据:
var obj = new mystructure()
{
fieldA = 4
,
fieldB = 0
,
fieldC = 16
,
fieldD = 9
};
和编组:
Int32 objsize = Marshal.SizeOf(typeof(mystructure));
Byte[] ret = new Byte[objsize];
IntPtr buff = Marshal.AllocHGlobal(objsize);
Marshal.StructureToPtr(obj, buff, true);
Marshal.Copy(buff, ret, 0, objsize);
Marshal.FreeHGlobal(buff);
我在 ret
变量中得到了这个数据布局:
[0]: 4
[1]: 0
[2]: 16
[3]: 0
[4]: 9
[5]: 0
[6]: 0
[7]: 0
所有数据都在你的开头对齐space,我如何在结尾对齐?请注意,它不同于使用 [FieldOffset]
属性。
我需要以下结果:
[0]: 4
[1]: 0
[2]: 0
[3]: 16
[4]: 0
[5]: 0
[6]: 0
[7]: 9
已更新 - 我的解决方案
public static void LittleEndianToBigEndian<T>(Byte[] data, Int32 startOffset = 0) where T : struct
{
LittleEndianToBigEndian(typeof(T), data, startOffset);
}
public static void LittleEndianToBigEndian(Type structType, Byte[] data, Int32 startOffset = 0)
{
if (!structType.IsValueType || structType.IsEnum || structType.IsPrimitive)
throw new ArgumentException("The conversion only supports struct types", "structType");
var validFieldsRule = new Func<FieldInfo, Boolean>(f =>
!f.IsStatic &&
f.FieldType != typeof(String) &&
f.FieldType != typeof(Byte) &&
f.FieldType != typeof(SByte) &&
(f.FieldType.IsArray || f.FieldType.IsValueType)
);
foreach (var field in structType.GetFields().Where(validFieldsRule))
{
var offset = Marshal.OffsetOf(structType, field.Name).ToInt32();
var effectiveOffset = startOffset + offset;
if (field.FieldType.GetFields().Any(validFieldsRule) && !field.FieldType.IsEnum)
{
LittleEndianToBigEndian(field.FieldType, data, effectiveOffset);
}
else if (field.FieldType.IsArray)
{
//to-do: deal with arrays!
}
else
{
Array.Reverse
(
data
,
effectiveOffset
,
Marshal.SizeOf
(
field.FieldType.IsEnum ?
Enum.GetUnderlyingType(field.FieldType)
:
field.FieldType
)
);
}
}
}
您的问题是关于字节顺序而不是对齐。字节顺序或 endianness 是关于最重要的字节是第一个还是最后一个。
Marshal.StructurePtr
使用底层的字节顺序 CPU 因为它假定您要调用非托管函数。
这可能对你有帮助Marshalling a big-endian byte collection into a struct in order to pull out values
基本上您必须手动创建字节数组。大端也称为 network byte order
。您可以使用 ipaddress.hosttonetworkorder 获取整数和长整数的正确格式。
我有以下结构:
[StructLayout(LayoutKind.Sequential)]
public struct mystructure
{
public Byte fieldA;
public Byte fieldB;
public UInt16 fieldC;
public UInt32 fieldD;
}
然后,填充数据:
var obj = new mystructure()
{
fieldA = 4
,
fieldB = 0
,
fieldC = 16
,
fieldD = 9
};
和编组:
Int32 objsize = Marshal.SizeOf(typeof(mystructure));
Byte[] ret = new Byte[objsize];
IntPtr buff = Marshal.AllocHGlobal(objsize);
Marshal.StructureToPtr(obj, buff, true);
Marshal.Copy(buff, ret, 0, objsize);
Marshal.FreeHGlobal(buff);
我在 ret
变量中得到了这个数据布局:
[0]: 4
[1]: 0
[2]: 16
[3]: 0
[4]: 9
[5]: 0
[6]: 0
[7]: 0
所有数据都在你的开头对齐space,我如何在结尾对齐?请注意,它不同于使用 [FieldOffset]
属性。
我需要以下结果:
[0]: 4
[1]: 0
[2]: 0
[3]: 16
[4]: 0
[5]: 0
[6]: 0
[7]: 9
已更新 - 我的解决方案
public static void LittleEndianToBigEndian<T>(Byte[] data, Int32 startOffset = 0) where T : struct
{
LittleEndianToBigEndian(typeof(T), data, startOffset);
}
public static void LittleEndianToBigEndian(Type structType, Byte[] data, Int32 startOffset = 0)
{
if (!structType.IsValueType || structType.IsEnum || structType.IsPrimitive)
throw new ArgumentException("The conversion only supports struct types", "structType");
var validFieldsRule = new Func<FieldInfo, Boolean>(f =>
!f.IsStatic &&
f.FieldType != typeof(String) &&
f.FieldType != typeof(Byte) &&
f.FieldType != typeof(SByte) &&
(f.FieldType.IsArray || f.FieldType.IsValueType)
);
foreach (var field in structType.GetFields().Where(validFieldsRule))
{
var offset = Marshal.OffsetOf(structType, field.Name).ToInt32();
var effectiveOffset = startOffset + offset;
if (field.FieldType.GetFields().Any(validFieldsRule) && !field.FieldType.IsEnum)
{
LittleEndianToBigEndian(field.FieldType, data, effectiveOffset);
}
else if (field.FieldType.IsArray)
{
//to-do: deal with arrays!
}
else
{
Array.Reverse
(
data
,
effectiveOffset
,
Marshal.SizeOf
(
field.FieldType.IsEnum ?
Enum.GetUnderlyingType(field.FieldType)
:
field.FieldType
)
);
}
}
}
您的问题是关于字节顺序而不是对齐。字节顺序或 endianness 是关于最重要的字节是第一个还是最后一个。
Marshal.StructurePtr
使用底层的字节顺序 CPU 因为它假定您要调用非托管函数。
这可能对你有帮助Marshalling a big-endian byte collection into a struct in order to pull out values
基本上您必须手动创建字节数组。大端也称为 network byte order
。您可以使用 ipaddress.hosttonetworkorder 获取整数和长整数的正确格式。