Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nativeint Bigarray seems to be unsigned

Tags:

arrays

c

int

ocaml

ffi

I want to return int-arrays from a C-library to a OCaml program. In order to do so, I thought I'd just wrap them in a Bigarray.Array1.t. Below is a small demo of the C-stubs:

/* nativeintarray.c */ 
#include <stdio.h>
#include <assert.h>

#include <caml/memory.h>
#include <caml/bigarray.h>

CAMLprim value make_array(value unit) {
  CAMLparam1(unit);
  int* a = calloc (1, sizeof(int));
  a[0] = -1;
  /* Create a C-style bigarray, yes it is a memory leak */
  CAMLreturn(caml_ba_alloc_dims(CAML_BA_NATIVE_INT | CAML_BA_C_LAYOUT, 1, a, 1));
}

My example program looks like this:

(* nativeintarray.ml *)
open Bigarray

(** Type for int arrays from/to C *)
type ivector = (nativeint, nativeint_elt, c_layout) Array1.t

external make_array : unit -> ivector = "make_array"

let () =
  Printf.printf "%nd\n" (make_array ()).{0}

Since nativeint is a signed integer, I expect the program to output -1, instead it gives:

% ocamlbuild nativeintarray_c.o                                        
Finished, 1 target (0 cached) in 00:00:00.
% ocamlbuild -package bigarray -lflags nativeintarray_c.o nativeintarray.native
Finished, 4 targets (0 cached) in 00:00:00.
% ./nativeintarray.native 
4294967295

As I said, I naively expected nativeint to match the int in my local C-compiler, but this is obviously not the case. Can somebody explain this?

Platform: Ocaml 4.02.3, gcc 6.1.1, all 64 bit

like image 636
choeger Avatar asked Aug 05 '16 07:08

choeger


2 Answers

Have you checked sizeof(int) is really 8 in your environment?

In Win64, OCaml 4.03.0 with x86_64-w64-mingw32-gcc (MinGW64 compiler of Cygwin), your code runs just you have described (prints 4294967295, instead of -1). There, sizeof(int) does not return 8 but 4.

Changing int by long long fixed the issue. I am not a C guru, so I may be wrong but OCaml's nativeint may not be int of the underlying C compiler.

like image 81
camlspotter Avatar answered Sep 25 '22 00:09

camlspotter


In C sizeof(int) may not be 8 on a 64-bit platform.

If you wish to use the nativeint type in your C bindings the simplest is to include <caml/config.h> and use the intnat type defined there.

So to rewrite your example:

/* nativeintarray.c */
#include <stdio.h>
#include <assert.h>

#include <caml/config.h>
#include <caml/memory.h>
#include <caml/bigarray.h>

CAMLprim value make_array(value unit) {
  CAMLparam1(unit);
  intnat* a = calloc (1, sizeof(intnat));
  a[0] = -1;
  /* Create a C-style bigarray, yes it is a memory leak */
  CAMLreturn(caml_ba_alloc_dims(CAML_BA_NATIVE_INT | CAML_BA_C_LAYOUT, 1, a, 1));
}
like image 37
Daniel Bünzli Avatar answered Sep 26 '22 00:09

Daniel Bünzli