【问题标题】:How can I create this struct in C#?如何在 C# 中创建此结构?
【发布时间】:2012-11-28 05:45:34
【问题描述】:

我正在尝试在这篇 msdn 文章中创建以下结构。我正在尝试学习整个 FieldOffset,但不知道从哪里开始。

我基本上是这样做的。

[StructLayout(LayoutKind.Explicit, Size=12)]
public struct DHCP_OPTION_DATA_ELEMENT {
    [FieldOffset(0)]
    public DHCP_OPTION_DATA_TYPE OptionType;
    [FieldOffset(4)]
    public byte ByteOption;
    [FieldOffset(4)]
    public uint WordOption;
    [FieldOffset(4)]
    public UInt32 DWordOption;
    [FieldOffset(4)]
    public UInt32 DWordDWordOption;
    [FieldOffset(4)]
    public uint IpAddressOption;
    [FieldOffset(4)]
    public IntPtr StringDataOption;
    [FieldOffset(4)]
    public DHCP_BINARY_DATA BinaryDataOption;
    [FieldOffset(4)]
    public DHCP_BINARY_DATA EncapsulatedDataOption;
    [FieldOffset(4)]
    public string Ipv6AddressDataOption;
}

但是,它对我咆哮,说明以下异常。

it contains an object field at offset 4 that is incorrectly aligned or 
overlapped by a non-object field.

【问题讨论】:

  • DHCP_OPTION_DATA_TYPEDHCP_BINARY_DATA 是什么?
  • @VMAtm 它在链接中说。
  • 你的回答都是合理的。我会评论说,将联合与结构分开要容易得多。将联合声明为具有显式布局的 C# 结构。不要指定Size。对所有元素使用FieldOffset(0)。然后将该联合类型包含在整个结构中。对于整体结构,使用默认的顺序布局。所以你实际上并不需要 StructLayout 属性。

标签: c# struct pinvoke unions


【解决方案1】:

将其视为 IntPtr,而不是字符串。

但是,当使用 IntPtr 时,请务必注意自己进行清理,因为您现在将使用非托管内存,因此 GC 不会帮助您,从而导致每个内存泄漏是时候传递这个结构了。

您很可能希望使用 Marshal.PtrToStringUni 函数,正如 shf301 在另一个答案中所建议的那样。

【讨论】:

  • 删除了我添加附加 MarshalAs 标签的建议,因为在这种情况下这实际上并不能解决问题。问题是由于重叠,而不是运行时错误地猜测类型。使用 Marshal.PtrToString* 方法,如果您将字段设为 IntPtr,您应该能够获得所需的内容。
  • 好的,解决了我的问题,现在我有另一个问题。
【解决方案2】:

错误

它在偏移量 4 处包含一个未正确对齐的对象字段或 被非对象字段重叠。

是由于将非对象 (blittable) 类型(例如 Uint32)与对象类型(不可 blittable)重叠。编组器无法处理。 marhshaler 不知道联合的哪个字段是有效的(因为它不知道如何解码OptionType 所以它不知道它是否应该编组一个字符串值或一个整数值。试图编组一个整数值到一个字符串会导致崩溃(因为一个整数值不会指向一个有效的字符串),所以编组器抛出异常而不是让你崩溃。

因此,您必须通过将字符串定义为IntPtr 并使用Marshal.PtrToStringUni()Marshal.PtrToStringAnsi() 来手动编组字符串。

您也可能对 DHCP_BINARY_DATA 有同样的问题。

【讨论】:

    【解决方案3】:

    你有这个代码:

    [FieldOffset(4)]
    public string Ipv6AddressDataOption;
    

    String 是引用类型(对象),其他字段是值类型(非对象)。所以你必须改变Ipv6AddressDataOption的偏移量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-26
      • 1970-01-01
      相关资源
      最近更新 更多