【问题标题】:F# P/Invoke Marshaling Recursive StructuresF# P/Invoke 编组递归结构
【发布时间】:2011-01-11 02:58:58
【问题描述】:

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

例如:

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# 中表示这些结构的任何其他方式。

提前感谢您的宝贵时间。

【问题讨论】:

    标签: f# pinvoke recursive-datastructures


    【解决方案1】:

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

    来定义
    type A = ... 
    and B = ...
    

    而不是

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

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

    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
    

    【讨论】:

    • 非常感谢!这做到了。一个问题 - 我从未见过 nativeptr 构造。 MSDN 没有很好的解释,谷歌代码搜索也没有产生任何启发性的 sn-ps。
    • @arachnid - nativeptr&lt;'t&gt; 是一种 F# 特定类型,用于处理指针。实际上,它只是System.IntPtr 的别名,但NativeInterop.NativePtr 模块提供了几个有用的函数,用于以强类型的方式与这些指针进行交互。
    猜你喜欢
    • 2012-01-21
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    • 2012-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多