我试图从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;;
答案 0 :(得分:4)
为了分配一些东西,你需要知道它的大小。在libyaml
库中yaml_parser_t
类型不是不透明的,因此使用这种类型的最正确的方法是将它在ctypes中声明为结构并描述其所有字段。在这种情况下,您可以使用allocate
函数来创建值。但是,如果你拒绝这样做,我会理解你的。 yaml_parser_t
结构庞大,生命太短暂。因为,无法在运行时发现结构的大小,您需要编写c stub函数,或者只需在库中对其进行编码。后者并不像人们想象的那么糟糕,因为大小应该仅在主要版本更改时更改,因为yaml_parser_t
明确地变为非不透明,并且被视为接口的一部分。
ctypes中有两个允许分配内存的函数,即allocate
和allocate_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
类型应该是不透明的,并且应该提供一个创建它的函数。但不幸的是,我们拥有的东西。