OCaml Ctypes:为输出参数分配结构

OCaml Ctypes: allocate structure for out argument

我想用 Ctypes 绑定以下函数 (ref.) :

gint
g_constant_info_get_value (GIConstantInfo *info,
                           GIArgument *value);

我在 OCaml 中定义了 GIArgument 结构如下:

GTypes.mli:

type argument_t
val argument: argument_t structure typ
val v_boolean: (bool, argument_t structure) field
val v_int8: (int, argument_t structure) field
val v_uint8: (Unsigned.uint8, argument_t structure) field
val v_int16: (int, argument_t structure) field
val v_uint16: (Unsigned.uint16, argument_t structure) field
val v_int32: (int32, argument_t structure) field
val v_uint32: (Unsigned.uint32, argument_t structure) field
val v_int64: (int64, argument_t structure) field
val v_uint64: (Unsigned.uint64, argument_t structure) field
val v_float: (float, argument_t structure) field
val v_double: (float, argument_t structure) field
val v_short: (int, argument_t structure) field
val v_ushort: (Unsigned.ushort, argument_t structure) field
val v_int: (int, argument_t structure) field
val v_uint: (Unsigned.uint, argument_t structure) field
val v_long: (Signed.long, argument_t structure) field
val v_ulong: (Unsigned.ulong, argument_t structure) field
val v_ssize: (PosixTypes.ssize_t, argument_t structure) field
val v_size: (PosixTypes.size_t, argument_t structure) field
val v_string: (string, argument_t structure) field
val v_pointer: (unit Ctypes_static.ptr option, argument_t structure) field

GTypes.ml :

type argument_t
let argument : argument_t structure typ = structure "GIArgument"
let v_boolean = field argument "v_boolean" (bool)
let v_int8 = field argument "v_int8" (int8_t)
let v_uint8 = field argument "v_uint8" (uint8_t)
let v_int16 = field argument "v_int16" (int16_t)
let v_uint16 = field argument "v_uint16" (uint16_t)
let v_int32 = field argument "v_int32" (int32_t)
let v_uint32 = field argument "v_uint32" (uint32_t)
let v_int64 = field argument "v_int64" (int64_t)
let v_uint64 = field argument "v_uint64" (uint64_t)
let v_float = field argument "v_float" (float)
let v_double = field argument "v_double" (double)
let v_short = field argument "v_short" (short)
let v_ushort = field argument "v_ushort" (ushort)
let v_int = field argument "v_int" (int)
let v_uint = field argument "v_uint" (uint)
let v_long = field argument "v_long" (long)
let v_ulong = field argument "v_ulong" (ulong)
let v_ssize = field argument "v_ssize" (PosixTypes.ssize_t)
let v_size = field argument "v_size" (size_t)
let v_string = field argument "v_string" (string)
let v_pointer = field argument "v_pointer" (ptr_opt void)
let () = seal argument

下面是函数的实现:

GIConstantInfo.mli :

val get_value:
  t structure ptr -> GITypes.argument_t structure ptr

GIConstantInfo.ml

let get_value info =
  let get_value_raw =
    foreign "g_constant_info_get_value"
      (ptr constantinfo @-> ptr GITypes.argument @-> returning int) in
  let arg_ptr = allocate_n GITypes.argument ~count:1 in
  let _ = get_value_raw info arg_ptr in
  arg_ptr

和测试:

  let test_get_value test_ctxt =
    constant_test (fun info ->
        let type_info = GIConstantInfo.get_type info in
        match GITypeInfo.get_tag type_info with
        | GITypes.Int32 -> let argument = GIConstantInfo.get_value info in
          let value = getf (!@argument) GITypes.v_int32 in
          assert_equal_int 511 (Int32.to_int value)
        | _ -> assert_equal_string "The tag should be " "Int32"
      )

问题是我无法获得 511 值,我有 0(我用另一种语言测试过它,所以我确定我应该获得的值)。我不知道怎么了:

我发现了问题,Gtk+ 文档不是很清楚,GIArgument 不是 structure,它是 [= 中定义的 union 50=].

union _GIArgument
{
  gboolean v_boolean;
  gint8    v_int8;
  guint8   v_uint8;
  gint16   v_int16;
  guint16  v_uint16;
  gint32   v_int32;
  guint32  v_uint32;
  gint64   v_int64;
  guint64  v_uint64;
  gfloat   v_float;
  gdouble  v_double;
  gshort   v_short;
  gushort  v_ushort;
  gint     v_int;
  guint    v_uint;
  glong    v_long;
  gulong   v_ulong;
  gssize   v_ssize;
  gsize    v_size;
  gchar *  v_string;
  gpointer v_pointer;
};

由于 Ctypes 处理 union 的方式与 structure 几乎相同,因此我能够使其与 :

一起使用

GTypes.mli :

type argument_t
val argument: argument_t union typ
val v_boolean: (bool, argument_t union) field
val v_int8: (int, argument_t union) field
val v_uint8: (Unsigned.uint8, argument_t union) field
val v_int16: (int, argument_t union) field
val v_uint16: (Unsigned.uint16, argument_t union) field
val v_int32: (int32, argument_t union) field
val v_uint32: (Unsigned.uint32, argument_t union) field
val v_int64: (int64, argument_t union) field
val v_uint64: (Unsigned.uint64, argument_t union) field
val v_float: (float, argument_t union) field
val v_double: (float, argument_t union) field
val v_short: (int, argument_t union) field
val v_ushort: (Unsigned.ushort, argument_t union) field
val v_int: (int, argument_t union) field
val v_uint: (Unsigned.uint, argument_t union) field
val v_long: (Signed.long, argument_t union) field
val v_ulong: (Unsigned.ulong, argument_t union) field
val v_ssize: (PosixTypes.ssize_t, argument_t union) field
val v_size: (PosixTypes.size_t, argument_t union) field
val v_string: (string, argument_t union) field
val v_pointer: (unit Ctypes_static.ptr option, argument_t union) field

GTypes.ml :

type argument_t
let argument : argument_t union typ = union "GIArgument"
let v_boolean = field argument "v_boolean" (bool)
let v_int8 = field argument "v_int8" (int8_t)
let v_uint8 = field argument "v_uint8" (uint8_t)
let v_int16 = field argument "v_int16" (int16_t)
let v_uint16 = field argument "v_uint16" (uint16_t)
let v_int32 = field argument "v_int32" (int32_t)
let v_uint32 = field argument "v_uint32" (uint32_t)
let v_int64 = field argument "v_int64" (int64_t)
let v_uint64 = field argument "v_uint64" (uint64_t)
let v_float = field argument "v_float" (float)
let v_double = field argument "v_double" (double)
let v_short = field argument "v_short" (short)
let v_ushort = field argument "v_ushort" (ushort)
let v_int = field argument "v_int" (int)
let v_uint = field argument "v_uint" (uint)
let v_long = field argument "v_long" (long)
let v_ulong = field argument "v_ulong" (ulong)
let v_ssize = field argument "v_ssize" (PosixTypes.ssize_t)
let v_size = field argument "v_size" (size_t)
let v_string = field argument "v_string" (string)
let v_pointer = field argument "v_pointer" (ptr_opt void)
let () = seal argument

GIConstantInfo.mli :

val get_value:
  t structure ptr -> GITypes.argument_t union ptr

GIConstantInfo.ml

let get_value info =
  let get_value_raw =
    foreign "g_constant_info_get_value"
      (ptr constantinfo @-> ptr GITypes.argument @-> returning int) in
  let arg_ptr = allocate_n GITypes.argument ~count:1 in
  let _ = get_value_raw info arg_ptr in
  arg_ptr

TL;DR:这是一个 union ,我只需将 structure 替换为 union.