无法从显式结构中访问变量(引发联合)C#

时间:2014-07-23 07:40:47

标签: c# struct unions

我正在尝试从C 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数组(intellisense显示'?')实例化之后无法访问uint byte,如下所示

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

3 个答案:

答案 0 :(得分:1)

行。这是因为您在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;
}

答案 1 :(得分:1)

MarshalAs属性不会改变.NET类/结构中数据的表示方式,它只会改变传递给其他代码时数据编组的方式。数组仍将是对数组的引用,并且它在那里变成了地狱。

您可以使用此方法覆盖两个不同类型的数组,但涉及一些严重的问题。最大的问题是所有阵列的元素数量都是相同的,但为阵列分配的内存量将是相同的。

以此联盟为例:

[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);

当然这是不正确的。如果我尝试访问ints数组中前25个条目之后的任何内容,我可能会收到严重错误并崩溃。

您当然可以将这些内容包装到私有字段中并公开适当的方法。要小心你实际访问数据的方式......因为如果你弄错了,你打破。

答案 2 :(得分:0)

为什么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];
}