OCaml使用字节码编译器从C函数返回未装箱的浮点数

时间:2017-09-23 19:41:19

标签: c ocaml ffi

我有一个非常简单的函数,调用time(2)以获取纪元时间并将其作为未装箱的OCaml浮点数返回。

这里的平台是OS X 10.12.6,我使用OCaml版本4.03.0和4.04.0进行了测试。

以下是libunixtime.c

#define CAML_NAME_SPACE
#include <time.h>
#include <caml/memory.h>

#define IGNORE_UNUSED(x) ( (void)(x) )

CAMLprim double
ocaml_unixtime(value unit)
{
    IGNORE_UNUSED(unit);
    return (double) time(NULL);
}

OCaml代码unixtime.ml看起来像这样......它返回一个未装箱的浮点数,并向编译器指示它不执行任何OCaml端分配。

这个函数只需要少于5个参数,所以看起来像实现它一次,并且对字节码编译器和本机编译器使用它应该没问题(https://caml.inria.fr/pub/docs/manual-ocaml/intfc.html#sec397)。

external unixtime : unit -> (float [@unboxed]) = 
  "ocaml_unixtime" "ocaml_unixtime" [@@noalloc];;

let () = Printf.printf "%f\n" (unixtime ())

此示例适用于本机编译器(尽管我有点担心转换为double不是完全正确的事情,但它在我的机器上工作)

% ocamlopt unixtime.ml libunixtime.c
% ./a.out
1506195346.000000

但是,在使用字节码编译器进行编译并尝试运行时,我会立即得到段错误。

% ocamlc -custom unixtime.ml libunixtime.c
% ./a.out
Segmentation fault
Exit 139

字节码编译器不支持未装箱的浮点数吗?我如何弄清楚为什么字节码和本机编译器之间的行为不同?

1 个答案:

答案 0 :(得分:3)

首先,您的代码似乎缺少对while ((new_socket = accept(s, (struct sockaddr*)&client, &c)) != INVALID_SOCKET) 值的CAMLparam调用。这是必要的,以便GC了解它,请参阅section 19.1

但还有另一个更重要的错误:字节码版本不能使用未装箱的函数(section 19.10),所以你必须为字节码编译器提供一个替代实现,它使用unit返回一个盒装值。和caml_copy_double