将 C 联合映射到 C# 结构

本文关键字:结构 映射 | 更新日期: 2023-09-27 18:36:18

>我正在尝试将 C 结构映射到 C# 以在包装类中使用它,但不断在结构上遇到 TypeLoadException,因为它:

包含偏移量 2 处的对象字段,该字段未正确对齐或与非对象字段重叠。

以下是相关的 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;
};  

我尝试过有和没有包=2。我尝试将联合移动到具有显式布局和字段偏移量为 0 的单独结构,然后在 IDTYPE 的布局顺序结构中使用该结构。我不太确定我哪里出错了?

将 C 联合映射到 C# 结构

最好为联合使用类型,然后将其与包含结构聚合。这允许框架布置类型并计算偏移量,除了将所有成员置于偏移量零的联合之外。

联合中的字节数组使事情变得更加复杂。这里的一个选项是使用固定缓冲区。

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

此选项确实允许您避免使用不安全的代码。