OCaml Ctypes并为类型分配指针

时间:2015-01-02 05:45:39

标签: ocaml ctypes

我试图从OCaml调用一些C代码,我需要为我的类型yaml_parser_t提供一个已分配的指针。但我不确定我应该如何分配有效的指针。示例代码如下。

理想情况下,我不想为yaml_parser_t提供具体的实施方案,因为我不需要检查它的内部,只需将其传入和传出各种功能。我最初关注的是Real World OCaml中的time_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;;

1 个答案:

答案 0 :(得分:4)

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

为抽象值分配数据

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

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

let size = 100
let alignment = 0

let yaml_parser_t : unit abstract typ =
  abstract ~name:"yaml_parser_t" ~size ~alignment

现在您可以使用yaml_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或其他类型并将其传递给存根。

P.S。 libyaml接口相当奇怪,这是问题的根源。 yaml_parser_t类型应该是不透明的,并且应该提供一个创建它的函数。但不幸的是,我们拥有的东西。