OCaml Ctypes并为类型分配指针

OCaml Ctypes并为类型分配指针,ocaml,ctypes,Ocaml,Ctypes,我试图从OCaml调用一些C代码,在这里我需要提供一个分配给我的类型yaml\u parser\t的指针。但我不确定应该如何分配有效指针。下面是示例代码 理想情况下,我也不想为yaml\u parser\t提供具体的实现,因为我不需要检查它的内部结构,只需将它传入和传出各种函数即可。我最初是按照中的time\u t示例进行的,但他们似乎在使用time函数来分配我在这里没有的时间 对不起,解释得很混乱 open PosixTypes;; open Ctypes;; open Foreign;;

我试图从OCaml调用一些C代码,在这里我需要提供一个分配给我的类型
yaml\u parser\t
的指针。但我不确定应该如何分配有效指针。下面是示例代码

理想情况下,我也不想为
yaml\u parser\t
提供具体的实现,因为我不需要检查它的内部结构,只需将它传入和传出各种函数即可。我最初是按照中的time\u t示例进行的,但他们似乎在使用
time
函数来分配我在这里没有的时间

对不起,解释得很混乱

open PosixTypes;;
open Ctypes;;
open Foreign;;

type yaml_parser_t = unit;;
let yaml_parser_t : yaml_parser_t typ = void;;

(* To get it working in utop, specify the name of the library *)
let libyaml = Dl.(dlopen ~filename:"libyaml.dylib" ~flags:[RTLD_NOW]);;

let init = foreign "yaml_parser_initialize" (ptr yaml_parser_t @-> returning int);;

let make =
    let p_ptr = allocate yaml_parser_t (from_voidp yaml_parser) in
    let _ = init p_ptr in
    p_ptr;;

为了分配一些东西,你需要知道它的大小。在
libyaml
库中,
yaml\u parser\u t
类型不是不透明的,因此处理此类类型的最正确方法是在ctypes中将其声明为结构并描述其所有字段。在这种情况下,只需使用
allocate
函数来创建值。但是,如果你拒绝这样做,我会理解你的。
yaml\u parser\t
结构庞大,生命周期太短。由于无法在运行时发现结构的大小,因此您需要编写c存根函数,或者在库中对其进行harcode。正如人们所想,后者并不是那么糟糕,因为大小应该只在主要版本更改时改变,因为
yaml_parser_t
被显式地设置为非不透明,并且被视为接口的一部分

为抽象值分配数据 ctypes中有两个函数允许分配内存,即
allocate
allocate\n
。前者需要分配值的实例。因为我们的类型是抽象的,所以我们将使用后者,因为它不需要我们提供值

首先,我们需要描述一个抽象类型。我们只需要提供三个值:名称、大小和对齐方式。名称很简单,可以是任意字符串。只有C编译器才能确定大小和对齐方式。最简单的方法是编写一个小程序,使用编译时指令的
sizeof
\uuu\uuu
打印它们。然后将输出复制粘贴到
ml
代码中。如果您发现这个解决方案是dirty,那么您可以编写两个原语c函数,它们将在运行时返回这个值。因此,假设您检索了这些值,那么我们现在可以为
yaml\u parser\t
创建一个类型:

let size = 100
let alignment = 0

let yaml_parser_t : unit abstract typ =
  abstract ~name:"yaml_parser_t" ~size ~alignment
现在,您可以使用
yaml\u parser\t
分配内存:

let allocate_yaml_parser () : unit abstract ptr =
  allocate_n yaml_parser_t ~count:1
然后您可以尝试分配它:

# let p = allocate_yaml_parser ();;
val p : unit Ctypes.abstract Ctypes.ptr = (yaml_parser_t*) 0x10156d0
接下来,您可以将其强制转换为void或其他类型,并将其传递给存根


另外,
libyaml
接口很奇怪,这是问题的根源。
yaml\u parser\t
类型应该是不透明的,并且应该提供一个创建它的函数。但不幸的是,我们拥有我们所拥有的

谢谢你对我的答案的评论,很明显我应该更仔细地查看代码。谢谢你的回答。我真的不想用OCaml描述整个结构,因为它又大又复杂,我不需要知道它的结构就可以使用它。我将如何对
yaml\u parser\u t
的大小值进行硬编码?是否需要使用类似
Buffer.create的东西并传入计算的大小?我是否可以安全地将其转换为一种类型的
yaml\u parser\t
?@lambda\u foo Ctypes自现实世界的OCaml问世以来添加了很多特性。我认为其中一些特性(特别是C存根生成)可以让您随心所欲。我建议问一下ctypes邮件列表(ctypes@lists.ocaml.org)@lambda_foo,我已经更新了这篇文章,说明了如何分配内存。@LeoWhite,我怀疑存根生成在这里是否有用。