Я пытаюсь построить явную struct
С# из C- union
. Явная структура:
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct struct_1
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public uint[] All32;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public struct_2[] bits;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct struct_2
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] Var56;
}
Это структуры, и я не могу получить доступ к All32
который является uint
после создания экземпляра из массива byte
(intellisense показывает "?") Следующим образом
Type structureType = typeof(struct_1);
byte[] b = new byte[4];
b[0] = 0xA0;
b[1] = 0x01;
b[2] = 0xF0;
b[3] = 0x00;
if (structureType != null)
{
try
{
GCHandle handle = GCHandle.Alloc(b, GCHandleType.Pinned);
struct_1 intpdObj = (struct_1)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), structureType);
handle.Free();
}
catch
{
}
}
ОК. Это связано с тем, что вы определили массив внутри struct_2
и это объект, поэтому адрес памяти будет помещен внутри этого местоположения, когда PtrToStructure
создает структуру. Вы можете попробовать следующее:
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct struct_1
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray)]
public uint[] All32;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.Struct)]
public struct_2 bits;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct struct_2
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] Var56;
}
Console.WriteLine(intpdObj.All32[0]);
MarshalAs
не изменит способ представления данных в вашем классе.NET/struct, он просто изменит способ маршализации данных при передаче другому коду. Массив все равно будет ссылкой на массив, и все это превращается в ад там.
Используя эти методы, вы можете наложить два массива разных типов, но есть серьезные серьезные проблемы. Самая большая проблема заключается в том, что количество элементов будет одинаковым для всех массивов, но объем памяти, выделяемый для массивов, будет таким же.
Возьмите этот союз, например:
[StructLayout(LayoutKind.Explicit)]
public struct ArrayUnion
{
[FieldOffset(0)]
public byte[] bytes;
[FieldOffset(0)]
public int[] ints;
}
Если я создам новый экземпляр этой структуры со 100-байтовым массивом, массив ints
также будет требовать иметь длину 100:
var u = new ArrayUnion { bytes = new byte[100] };
Console.WriteLine(u.ints.Length);
Это, конечно, неверно. Если я попытаюсь получить доступ к чему-либо из первых 25 записей в массиве ints
я, вероятно, получу серьезную ошибку и ints
краха.
Вы можете, конечно, перенести некоторые из этих материалов в частные поля и выставить соответствующие методы. Просто будьте осторожны, как вы действительно получаете доступ к данным... потому что, если вы ошибетесь, вы нарушите все.
unsafe
код и небезопасный код. Это второй тип: P С другой стороны, это самый быстрый способ преобразования байтового массива произвольной длины обратно в целые числа (или двойные числа, или что угодно), которые он представляет, без использования unsafe
. Это хак, но это не будет работать , если вы будете осторожны с ним и знать риски.
Почему All32
- массив? Что произойдет, если вы попробуете что-то подобное?
[StructLayout( LayoutKind.Explicit, Pack = 1 )]
public unsafe struct struct_1
{
[FieldOffset( 0 )]
public uint All32;
[FieldOffset( 0 )]
public fixed byte bits[4];
}
Изменение: если вы хотите, чтобы All32
был массивом:
[StructLayout( LayoutKind.Explicit, Pack = 1 )]
public unsafe struct struct_1
{
[FieldOffset( 0 )]
public fixed uint All32[1];
[FieldOffset( 0 )]
public fixed byte bits[4];
}
Marshal.PtrToStructure
союзов и Marshal.PtrToStructure
в C # в любом случае не очень далеко от небезопасной территории кода.
catch
может подавлять ценную отладочную информацию.