Introduction au dialogue entre OCaml et le C
|
Par
Cacophrene
Mise à jour : 15/11/2009
25 visites depuis 7 jours
, classé 733/777
|
$ ls $(ocamlc -where)/caml alloc.h compatibility.h fail.h misc.h bigarray.h config.h intext.h mlvalues.h callback.h custom.h memory.h printexc.h |
| Fichier d'en-tête | Contenu |
| mlvalues.h | Macros et fonctions usuelles, type value |
| fail.h | Lever des exceptions |
| alloc.h | Allouer de la mémoire |
| memory.h | Dialoguer avec le GC |
1 2 3 4 5 6 7 8 9 10 | #include <caml/mlvalues.h> #include <caml/memory.h> #include <stdio.h> CAMLprim value caml_hello(value unit) { CAMLparam1(unit); printf("Hello world!\n"); CAMLreturn(Val_unit); } |
1 2 3 | external hello : unit -> unit = "caml_hello" let _ = hello () |
Il ne reste plus qu'à compiler. Dans tous les exemples que nous allons présenter ici, c'est une étape facile puisqu'il suffit de passer les deux fichiers au compilateur OCaml (si vous voulez savoir ce qui se passe, utilisez l'option -verbose) :
)| Commande/Macro | Fonction |
| CAMLprim | Introduit une fonction C accessible depuis OCaml |
| CAMLparamN | Protéger les N arguments reçus en entrée |
| CAMLreturn | Renvoyer un résultat (de type value) dans le monde OCaml |
| Val_unit | value (unit OCaml) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <caml/mlvalues.h> #include <caml/memory.h> CAMLprim value caml_and(value x, value y) { CAMLparam2(x, y); int res = Bool_val(x) && Bool_val(y); CAMLreturn(Val_bool(res)); } CAMLprim value caml_or(value x, value y) { CAMLparam2(x, y); int res = Bool_val(x) || Bool_val(y); CAMLreturn(Val_bool(res)); } |
1 2 3 4 5 6 7 | external my_and : bool -> bool -> bool = "caml_and" external my_or : bool -> bool -> bool = "caml_or" let _ = let print = Printf.printf "Résultat : %B\n%!" in print (my_and true false); print (my_or false true) |
Testons sans tarder notre code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <caml/mlvalues.h> #include <caml/memory.h> CAMLprim value caml_succ(value x) { CAMLparam1(x); int res = Int_val(x) + 1; CAMLreturn(Val_int(res)); } CAMLprim value caml_prev(value x) { CAMLparam1(x); int res = Int_val(x) - 1; CAMLreturn(Val_int(res)); } |
1 2 3 4 5 6 | external succ : int -> int = "caml_succ" external prev : int -> int = "caml_prev" let _ = let n = 25 in Printf.printf "Résultat : %d < %d < %d\n%!" (pred n) n (succ n) |
| Commande/Macro | Fonction |
| Int_val | value vers entier C |
| Val_int | Entier C vers value (entier OCaml) |
| Bool_val | value vers entier C (0 ou 1) |
| Val_bool | Entier C vers value (booléen OCaml) |
| Val_true | value (booléen OCaml true) |
| Val_false | value (booléen OCaml false) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <math.h> #include <caml/mlvalues.h> #include <caml/memory.h> #include <caml/alloc.h> CAMLprim value caml_exp(value x) { CAMLparam1(x); double res = exp(Double_val(x)); CAMLreturn(caml_copy_double(res)); } CAMLprim value caml_exp(value x) { CAMLparam1(x); double res = log(Double_val(x)); CAMLreturn(caml_copy_double(res)); } |
1 2 3 4 5 6 | external my_exp : float -> float = "caml_exp" external my_log : float -> float = "caml_log" let _ = let resultat = my_exp 1.0 in Printf.printf "Résultat : %.4f %.4f\n%!" (log resultat) (my_log resultat) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <ctype.h> #include <caml/mlvalues.h> #include <caml/memory.h> #include <caml/alloc.h> CAMLprim value caml_uppercase(value s) { CAMLparam1(s); int i; char *str = String_val(s); for(i = 0; i < caml_string_length(s); i++) str[i] = toupper(str[i]); CAMLreturn(s); } |
1 2 3 | external uppercase : string -> string = "caml_uppercase" let _ = print_endline (uppercase "Hello world!") |
| Commande/Macro | Fonction |
| Double_val | value vers flottant C |
| caml_copy_double | Flottant C vers value (flottant OCaml) |
| String_val | value vers char* |
| caml_string_length | Renvoie la longueur d'une chaîne OCaml (type value) sous forme d'entier C |
| caml_copy_string | char* C vers value (chaîne OCaml) |
1 2 3 4 5 6 7 8 9 10 11 12 | #include <math.h> #include <caml/mlvalues.h> #include <caml/memory.h> #include <caml/alloc.h> CAMLprim value caml_approx_pi(value unit) { CAMLparam1(unit); CAMLlocal1(approx_pi); approx_pi = caml_copy_double(acos(-1)); CAMLreturn(approx_pi); } |
1 2 3 | external approx_pi : unit -> float = "caml_approx_pi" let _ = Printf.printf "pi = %.12f\n%!" (approx_pi ()) |
) :| Commande/Macro | Fonction |
| CAMLparamN | Préserve les valeurs reçues en entrée |
| CAMLlocalN | Définit des valeurs locales de type value |
| CAMLreturn | Renvoie une valeur de type value |
1 2 3 4 5 6 7 8 9 10 11 | #include <caml/mlvalues.h> #include <caml/memory.h> #include <caml/fail.h> CAMLprim value caml_triplet_nth(value triplet, value n) { CAMLparam2(triplet, n); int i = Int_val(n); if (i < 0 || i > 2) caml_invalid_argument("triplet_nth"); CAMLreturn(Field(triplet, i)); } |
1 2 3 4 5 6 | external triplet_nth : float * float * float -> int -> float = "caml_triplet_nth" let _ = let x = (1.6, 3.2, 7.5) in Printf.printf "x = (%.1f, %.1f, %.1f)\n%!" (triplet_nth x 0) (triplet_nth x 1) (triplet_nth x 2) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <caml/mlvalues.h> #include <caml/memory.h> #include <caml/alloc.h> CAMLprim value caml_triplet(value unit) { CAMLparam1(unit); CAMLlocal1(triplet); triplet = caml_alloc_tuple(3); Store_field(triplet, 0, Val_true); Store_field(triplet, 1, caml_copy_double(3.14)); Store_field(triplet, 2, Val_int(65)); CAMLreturn(triplet); } |
1 2 3 4 5 | external triplet : unit -> bool * float * char = "caml_triplet" let _ = let x, y, z = triplet () in Printf.printf "(%b, %.2f, %C)\n%!" x y z |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <stdio.h> #include <caml/mlvalues.h> #include <caml/memory.h> CAMLprim value caml_inspect_list(value list) { CAMLparam1(list); CAMLlocal1(head); while (list != Val_emptylist) { head = Field(list, 0); printf("%s\n", String_val(head)); list = Field(list, 1); } CAMLreturn(Val_unit); } |
1 2 3 | external inspect_list : string list -> unit = "caml_inspect_list" let _ = inspect_list ["Hello"; "world"; "!"] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <caml/mlvalues.h> #include <caml/memory.h> #include <caml/alloc.h> CAMLprim value caml_explode(value s) { CAMLparam1(s); CAMLlocal2(list, cons); list = Val_emptylist; int i; char* str = String_val(s); for(i = caml_string_length(s); i; i--) { cons = caml_alloc(2, 0); Store_field(cons, 0, Val_int(str[i - 1])); Store_field(cons, 1, list); list = cons; } CAMLreturn(list); } |
1 2 3 4 5 6 7 | external explode : string -> char list = "caml_explode" let _ = let str = read_line () in Printf.printf "[ "; List.iter (Printf.printf "%C ") (explode str); Printf.printf "]\n%!" |
| Commande/Macro | Fonction |
| Field(v, n) | Renvoie le champ n (entier C) de la valeur v (type value) |
| Store_field(v, n, x) | Enregistre la valeur x (type value) dans le champ n (entier C) de la valeur v (type value) |
| caml_alloc(n, tag) | Alloue un bloc de taille n (entier C) contenant l'étiquette tag (entier C) |
| caml_alloc_tuple(i) | Alloue de la mémoire pour un n-uplet contenant i champs |
| caml_alloc_string(n) | Alloue de la mémoire pour une chaîne de caractères de longueur n. La chaîne est initialisée avec des données quelconques. |
1 2 3 4 5 6 7 8 9 | #include <caml/mlvalues.h> #include <caml/memory.h> CAMLprim value caml_succ(value n) { CAMLparam1(n); int res = Int_val(n) + 1; CAMLreturn(res); } |
1 2 3 4 5 | external succ : int -> int = "caml_succ" let _ = let n = 3 in Printf.printf "succ %d = %d\n%!" n (succ n) |
$ ocamlopt int_stub.c int.ml -o int $ ./int succ 4 = 2 $ |
1 2 3 4 5 6 7 8 | #include <caml/mlvalues.h> #include <caml/memory.h> CAMLprim value caml_nth_tuple(value tuple, value n) { CAMLparam2(tuple, n); CAMLreturn(Field(tuple, Int_val(n) - 1)); } |
1 2 3 4 5 | external nth_tuple : 'a -> int -> 'b = "caml_nth_tuple" let _ = let tuple = (1, "oui", true, None) in Printf.printf "Résultat : %s\n%!" (nth_tuple tuple 3) |
$ ocamlopt crash_stub.c crash.ml -o crash $ ./crash Erreur de segmentation $ |