将 C 联合映射到 C# 结构
Mapping C Union to C# struct
我正在尝试将 C 结构映射到 C# 以在包装器中使用它 class 但将 运行 保留在结构上的 TypeLoadException 中,因为它:
contains an object field at offset 2 that is incorrectly aligned or overlapped by a non-object field.
这里是相关的 C 代码:
#pragma pack(2)
tyedef unsigned char SPECIAL_ID[16];
typedef struct _idType
{
unsigned char f;
unsigned char t;
union
{
unsigned short i_legacy;
SPECIAL_ID i;
}
} IDTYPE;
这是对 C# 结构的最新尝试:
[StructLayout(LayoutKind.Explicit, Pack=2)]
public struct IDTYPE
{
[FieldOffset(0)]
public System.Byte f;
[FieldOffset(1)]
public System.Byte t;
[FieldOffset(2)]
public ushort i_legacy;
[FieldOffset(2)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
public StringBuilder i;
};
我试过使用和不使用 Pack=2。我已经尝试将联合移出到具有显式布局和字段偏移量 0 的单独结构,然后在 IDTYPE 的布局顺序结构中使用该结构。我不太确定哪里出错了?
最好为联合使用一个类型,然后将它与包含的结构聚合。这让框架可以布置类型并计算偏移量,除了将所有成员放置在偏移量零处的联合之外。
联合中的字节数组使事情变得更加复杂。这里的一种选择是使用固定缓冲区。
[StructLayout(LayoutKind.Explicit)]
public unsafe struct IDTYPE_UNION
{
[FieldOffset(0)]
public ushort i_legacy;
[FieldOffset(0)]
public fixed byte i[16];
};
像这样把它放在包含结构中:
[StructLayout(LayoutKind.Sequential, Pack=2)]
public struct IDTYPE
{
public byte f;
public byte t;
public IDTYPE_UNION union;
};
另一种选择是简单地省略 i_legacy
成员,如果您确实需要读取该数据,请从字节数组中读取:
[StructLayout(LayoutKind.Sequential, Pack=2)]
public struct IDTYPE
{
public byte f;
public byte t;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=16)]
public byte[] i;
ushort i_legacy
{
get
{
return (ushort)((ushort)i[0] << 8 | (ushort)i[1]);
}
}
};
此选项确实允许您避免使用不安全的代码。
我正在尝试将 C 结构映射到 C# 以在包装器中使用它 class 但将 运行 保留在结构上的 TypeLoadException 中,因为它:
contains an object field at offset 2 that is incorrectly aligned or overlapped by a non-object field.
这里是相关的 C 代码:
#pragma pack(2)
tyedef unsigned char SPECIAL_ID[16];
typedef struct _idType
{
unsigned char f;
unsigned char t;
union
{
unsigned short i_legacy;
SPECIAL_ID i;
}
} IDTYPE;
这是对 C# 结构的最新尝试:
[StructLayout(LayoutKind.Explicit, Pack=2)]
public struct IDTYPE
{
[FieldOffset(0)]
public System.Byte f;
[FieldOffset(1)]
public System.Byte t;
[FieldOffset(2)]
public ushort i_legacy;
[FieldOffset(2)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
public StringBuilder i;
};
我试过使用和不使用 Pack=2。我已经尝试将联合移出到具有显式布局和字段偏移量 0 的单独结构,然后在 IDTYPE 的布局顺序结构中使用该结构。我不太确定哪里出错了?
最好为联合使用一个类型,然后将它与包含的结构聚合。这让框架可以布置类型并计算偏移量,除了将所有成员放置在偏移量零处的联合之外。
联合中的字节数组使事情变得更加复杂。这里的一种选择是使用固定缓冲区。
[StructLayout(LayoutKind.Explicit)]
public unsafe struct IDTYPE_UNION
{
[FieldOffset(0)]
public ushort i_legacy;
[FieldOffset(0)]
public fixed byte i[16];
};
像这样把它放在包含结构中:
[StructLayout(LayoutKind.Sequential, Pack=2)]
public struct IDTYPE
{
public byte f;
public byte t;
public IDTYPE_UNION union;
};
另一种选择是简单地省略 i_legacy
成员,如果您确实需要读取该数据,请从字节数组中读取:
[StructLayout(LayoutKind.Sequential, Pack=2)]
public struct IDTYPE
{
public byte f;
public byte t;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=16)]
public byte[] i;
ushort i_legacy
{
get
{
return (ushort)((ushort)i[0] << 8 | (ushort)i[1]);
}
}
};
此选项确实允许您避免使用不安全的代码。