OCaml Ctypes 和分配一个指向类型的指针
OCaml Ctypes and allocating a pointer to a type
我正在尝试从 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;;
为了分配一些东西,您需要知道它的大小。在 libyaml
库中,yaml_parser_t
类型不是不透明的,因此使用这种类型最正确的方法是在 ctypes 中将其声明为结构并描述其所有字段。在这种情况下,您可以只使用 allocate
函数来创建值。但是,如果你拒绝这样做,我会理解你。 yaml_parser_t
结构巨大,生命太短暂。由于无法在运行时发现结构的大小,因此您需要编写 C 存根函数,或者只是在您的库中对其进行硬编码。后者并没有那么糟糕,正如人们可能认为的那样,因为大小只应在主要版本更改时更改,因为 yaml_parser_t
已明确设为非不透明,并被视为界面的一部分。
为抽象值分配数据
ctypes 中有两个函数可以分配内存,即allocate
和allocate_n
。前者需要分配值的实例。由于我们的类型是抽象的,我们将使用后者,因为它不需要我们提供值。
首先我们需要描述一个抽象类型。我们只需要提供三个值:名称、大小和对齐方式。名字很简单,可以是任意字符串。只有 C 编译器才能确定大小和对齐方式。最简单的方法是编写一个小程序,使用 sizeof
和 __alignof__
编译时指令打印它们。然后将输出复制粘贴到您的 ml
代码中。如果你发现这个解决方案很脏,那么你可以编写两个原始的 c 函数,在运行时将 return 这个值。因此,假设您已经检索了这些值,那么我们现在可以为 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
类型应该是不透明的,并且应该提供一个创建它的函数。但是,不幸的是,我们拥有我们所拥有的。
我正在尝试从 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;;
为了分配一些东西,您需要知道它的大小。在 libyaml
库中,yaml_parser_t
类型不是不透明的,因此使用这种类型最正确的方法是在 ctypes 中将其声明为结构并描述其所有字段。在这种情况下,您可以只使用 allocate
函数来创建值。但是,如果你拒绝这样做,我会理解你。 yaml_parser_t
结构巨大,生命太短暂。由于无法在运行时发现结构的大小,因此您需要编写 C 存根函数,或者只是在您的库中对其进行硬编码。后者并没有那么糟糕,正如人们可能认为的那样,因为大小只应在主要版本更改时更改,因为 yaml_parser_t
已明确设为非不透明,并被视为界面的一部分。
为抽象值分配数据
ctypes 中有两个函数可以分配内存,即allocate
和allocate_n
。前者需要分配值的实例。由于我们的类型是抽象的,我们将使用后者,因为它不需要我们提供值。
首先我们需要描述一个抽象类型。我们只需要提供三个值:名称、大小和对齐方式。名字很简单,可以是任意字符串。只有 C 编译器才能确定大小和对齐方式。最简单的方法是编写一个小程序,使用 sizeof
和 __alignof__
编译时指令打印它们。然后将输出复制粘贴到您的 ml
代码中。如果你发现这个解决方案很脏,那么你可以编写两个原始的 c 函数,在运行时将 return 这个值。因此,假设您已经检索了这些值,那么我们现在可以为 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
类型应该是不透明的,并且应该提供一个创建它的函数。但是,不幸的是,我们拥有我们所拥有的。