2

到目前为止,我所看到的示例似乎都没有解决封送包含递归引用的结构联合的结构的问题。我正在尝试为包含这些但迄今为止失败的结构编写一个封送拆收器。

例如:

typedef enum {
    My_StructA = 0x7878,
    My_StructB
} MyStructTag;

 typedef struct _MyStruct MyStruct;  

 struct _MyStruct {  
     MyStructTag discriminator;  
     union {  
        struct {  
            int a;  
            int b;  
        } StructA;  

        struct {  
            int c;  
            MyStruct* d;  
        } StructB;
    } MyUnion;  
};

我试图将结构定义如下:

type MyStructTag =
    | My_StructA = 0x7878
    | My_StructB = 0x7879

[<Struct; StructLayout(LayoutKind.Sequential)>]
type StructA =
    val mutable a : int
    val mutable b : int

[<Struct; StructLayout(LayoutKind.Sequential)>]
type StructB =
    val mutable c : int
    val mutable d : MyStruct

[<Struct; StructLayout(LayoutKind.Explicit)>]
type MyStruct =
    [<FieldOffset(0)>] val discriminator : MyStructTag
    [<FieldOffset(4)>] val structA : StructA
    [<FieldOffset(4)>] val structB : StructB

请注意,我费心显式定义 MyStruct 的原因是允许自己在为此结构编写自定义封送器时使用 Marshal.OffsetOf() 和 Marshal.SizeOf()。据我所知,编写自定义封送器是处理联合的唯一方法。如果我错了,参考将不胜感激!

编写上述代码时收到的错误是:

error FS0039: The type 'MyStruct' is not defined

我认为这是因为只能递归定义有区别的联合类型。但是,我不知道在 F# 中表示这些结构的任何其他方式。

提前感谢您的宝贵时间。

4

1 回答 1

4

你有两个问题。首先,任何相互递归的类型(无论是有区别的联合、类还是结构)都需要使用定义

type A = ... 
and B = ...

而不是

type A = ... 
type B = ...

(请注意,属性可以出现在单词之前或之后type,但只能在单词之后and......)。然而,如果你尝试这个,你会发现你只是得到一个不同的错误,因为结构不能直接递归作为彼此的字段。如果结构 A 有一个结构 B 的字段,而结构 B 有一个结构 A 的字段(并且它们中的任何一个都有任何其他字段),那么大小将是无限的。请注意,您的 C 代码也是如此 -StructB包含指向 a 的指针MyStruct而不是 aMyStruct本身。在 .NET 中,您可以IntPtr为此使用 - 在 F# 中,您可以使用nativeint别名或nativeptr<MyStruct>. 试试这个:

open System.Runtime.InteropServices

type MyStructTag =
| My_StructA = 0x7878
| My_StructB = 0x7879

[<Struct; StructLayout(LayoutKind.Sequential)>]
type StructA =
  val mutable a : int
  val mutable b : int

[<Struct; StructLayout(LayoutKind.Sequential)>]
type StructB =
  val mutable c : int
  val mutable d : nativeptr<MyStruct>

and [<Struct; StructLayout(LayoutKind.Explicit)>]MyStruct =
    [<FieldOffset(0)>] val discriminator : MyStructTag
    [<FieldOffset(4)>] val structA : StructA
    [<FieldOffset(4)>] val structB : StructB
于 2011-01-11T03:41:25.707 回答