Struct未正确对齐:System.TypeLoadException

时间:2014-10-06 21:12:58

标签: c# struct marshalling typeloadexception structlayout

我正在尝试在C#中创建以下结构,它是一个基于C语言的复杂结构,我尝试了大多数编组选项,但我总是得到'System.TypeLoadException'。

(附加信息:无法从程序集'WindowsFormsApplication1,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null'加载类型'WindowsFormsApplication1.COMPLEX_STRUCT',因为它包含偏移量为8的对象字段未正确对齐或重叠通过非对象字段。)

关于IPV6_ADDR结构,我尝试了LayoutKind.Explicit和LayoutKind.Sequential, 和两者:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string Addr;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] Addr;

我在x64机器上,但IPV6_ADDR结构对齐到8个字节,所以我无法弄清楚是什么问题。

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IPV4_ADDR
{
    public uint Addr;
    public uint SubnetNumBits;
};

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct IPV6_ADDR
{
    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
    public string Addr;
    [FieldOffset(16)]
    public uint SubnetNumBits;
};

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct COMPLEX_STRUCT
{
    [FieldOffset(0)]
    public byte A;

    [FieldOffset(1)]
    public byte B;

    [FieldOffset(2)]
    public byte C;

    [FieldOffset(3)]
    public byte D;

    [FieldOffset(4)]
    public byte E;

    [FieldOffset(8)]
    public IPV4_ADDR IPv4;

    [FieldOffset(8)]
    public IPV6_ADDR IPv6;

    [FieldOffset(28)]
    public ushort F;
}

我试图模仿的原始C结构:

typedef struct _IPV4_ADDR
{
    uint32_t Addr;
    uint32_t SubnetNumBits;
} IPV4_ADDR, *PIPV4_ADDR;

typedef struct _IPV6_ADDR
{
    uint8_t  Addr[16];
    uint32_t SubnetNumBits;
} IPV6_ADDR, *PIPV6_ADDR;

typedef struct _COMPLEX_STRUCT
{
    uint8_t A;
    uint8_t B;
    uint8_t C;
    uint8_t D;
    uint8_t E;
    uint8_t Rsvd[3];
    union {
        IPV4_ADDR IPv4;
        IPV6_ADDR IPv6;
    } u;
    uint16_t F;
} COMPLEX_STRUCT, *PCOMPLEX_STRUCT;

1 个答案:

答案 0 :(得分:1)

在查看原始结构并查看IPV4和IPV6结构的其他实现之后,我发现其他实现使用byte[4]作为IPV4的地址。

我无法保证结果是正确的,但如果您能够将IPV4和IPV6更改为使用byte[],则您的错误将消失。

你找不到混合搭配。我能想到的另一个选择是查看它是否允许您使用IntPtr来获取内存的位置,然后使用Marshal.Copy来获取数据。

即使你让它们工作,我也不能保证你的结果是正确的。