Communication Ocaml et C
Ce billet a pour but de montrer comment récupérer un tableau alloué dynamiquement en Ocaml dans un programme écrit en C. En regardant la doc de l'INRIA sur l'interfaçage entre du C et du Ocaml, on ne retrouvait des exemples qu'avec des types (Int, Char, String, ...) mais pour ma part, il fallait que je passe du type Char Array Array (Ocaml) à char ** (C). C'est en regardant du côté du module BigArray, que l'on peut voir qu'il existe un module Bigarray.Array2 permettant la manipulation des tableaux à 2 dimensions facilement.
Les BigArray peuvemt manipuler du type Char :
val char : (char, int8_unsigned_elt) kind
Et un layout permettant l'interportabilité avec le C :
type c_layout
A partir de tous ces éléments j'étais en mesure d'écrire un programme de test :
Code Ocaml :
(* Function just for Allocating our 2D table *) let create_tab n m init = let tab = Array.make n (Array.make m init) in for i = 1 to n - 1 do tab.(i) <- Array.make m init done; tab (* Function for creating the table and returning it *) let create_tab () = Random.self_init(); let tab = create_tab 20 30 'X' in init_tab tab; Bigarray.Array2.of_array Bigarray.char Bigarray.c_layout tab (* Export "create_tab" function to C *) let _ = Callback.register "create_tab callback" create_tab
Code C :
#include <stdio.h> #include <stdlib.h> #include <caml/mlvalues.h> #include <caml/callback.h> #include <caml/bigarray.h> /* I return my Char array array allocated in ocaml like this Bigarray.Array2.of_array Bigarray.char Bigarray.c_layout tab */ int test() { /* 2d table */ char **tab; /* simpli value for counting */ int i,j,k=0; /* Widht , height */ int w,h; /* pointer to data part */ char *p; /* pointer to the value registered under a name */ static value *f = NULL; f = caml_named_value("create_tab callback"); /* Applies the functional value f and return the value returned by f */ value ret = caml_callback(*f,Val_unit); /* i-th dimension Get the Width & Height */ w = Bigarray_val(ret)->dim[0]; h = Bigarray_val(ret)->dim[1]; /* We look is everything ok ? */ printf("\nw = %d\n",w); printf("\nh = %d\n",h); /* Get a pointer to the data part of the array */ p = Data_bigarray_val(ret); /* Ok now we alloc enough place */ tab = (char**)malloc(sizeof(char*)*w); if(!tab) return 1; for(i=0;i<w;i++) { tab[i] = (char*)malloc(sizeof(char)*h); if(!tab) return 1; } /* Here we copy everyhting in a table of 2 dimension More easier to manipulate it no ? */ for(i=0;i<w;i++) for(j=0;j<h;j++) { tab[i][j] = p[k]; k++; } /* And now we watch if everything is ok */ for(i=0;i<w;i++) { for(j=0;j<h;j++) printf("%c | ",tab[i][j]); printf("\n"); } } int main(int argc,char **argv) { caml_startup(argv); test(); return 0; }
Vous êtes en mesure maitenant de faire communiquer vos programmes Ocaml avec des programmes en C tout en manipulant des tableaux à X dimensions. X dimensions, Oui, car si vous lisez bien les pages du manuel que je vous ai linké, vous verrez que cela est possible.