2011-01-11 82 views
2

到目前为止,我所见过的任何示例似乎都没有解决编组包含递归引用的结构联合的结构的问题。我正试图为包含这些结构的结构编写一个编组器,并且迄今为止失败了。F#P /调用封送递归结构

例如:

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的原因是为了让自己充分利用元帅。 OffsetOf()和Marshal.SizeOf()为此结构编写自定义封送拆分器时。从我看到的情况来看,编写自定义编组器是处理工会的唯一方法。如果我错了,参考将不胜感激!

写上面的代码时,收到的错误是:

error FS0039: The type 'MyStruct' is not defined 

我假定这是因为只有识别联合类型可以被递归地定义。但是,我不知道有任何其他方式来表示F#中的这些结构。

预先感谢您的时间。

回答

4

你有两个问题。首先,任何相互递归类型(是否可识别联合,类或结构)需要使用

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

而不是

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

(请注意,属性可以来之前或之后的定义单词type,但仅在单词and ...之后)。但是,如果你尝试这样做,你会发现你只是得到了一个不同的错误,因为结构不能直接作为对方的字段递归。如果结构A具有一个结构B的字段,并且结构B具有一个结构A的字段(并且其中任何一个具有任何其他字段),那么大小将是无限的。请注意,您的C代码也是如此 - StructB包含指针MyStruct,而不是MyStruct本身。在.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 
+0

非常感谢!这做到了。一个问题 - 我从来没有见过nativeptr <|在这里插入非托管类型|>结构。 MSDN没有一个很好的解释,谷歌代码搜索没有产生任何启发性的片段。 – arachnid 2011-01-11 18:36:43