Hi David, I'm about to start generating code that makes calls to C via the low-level FFI. I was planning to use a form where parameters that provide return values are temporary vols created by alloc, as shown in the example SML code below (as suggested in the C interface documentation). However, it appears that the high-level FFI implementation doesn't do things this way - it uses call_sym_and_convert. Is that more efficient and should I be looking at that?
Using the alloc form works when a parameter is both and input and an output: in the example C code below, the second parameter `pos` is an in-out. I notice that call_sym_and_convert doesn't have an InOut constructor for Union.directedArg. This appears to be a problem for ML types that are not a vol (i.e. not passed by reference in the C FFI) such as int. Is there a way around this?
Thanks, Phil
/* -- C -- */
#include <string.h>
#define TRUE (0 == 0) #define FALSE (0 != 0)
/* get_next (s, pos, c) copies the character at offset pos in string s * to c, increments pos and returns TRUE, if pos is a valid index into s. * If pos is not a valid index, the function returns FALSE without * incrementing pos or writing to c. */ int get_next (const char *s, /* in */ int *pos, /* in out */ char *c) /* out */ { int len = strlen (s); if (0 <= *pos && *pos < len) { *c = s[*pos]; (*pos)++; return TRUE; } else { return FALSE; } }
(* -- SML -- *)
open CInterface
val lib = load_lib "testlib.so.1"
val (fromCbool, toCbool, Cbool) = breakConversion BOOL val Cstring = Cpointer Cchar
val get_next = fn (in1, in2) => let val sym = load_sym lib "get_next" val tmp2 = alloc 1 Cint val tmp3 = alloc 1 Cchar val () = assign Cint tmp2 (toCint in2) val args = [ (Cstring, toCstring in1), (Cpointer Cint, address tmp2), (Cpointer Cchar, address tmp3) ] val res = fromCbool (call_sym sym args Cbool) val out2 = fromCint tmp2 val out3 = fromCchar tmp3 in (res, out2, out3) end;
get_next ("hello", 0); get_next ("hello", 1); get_next ("hello", 2); get_next ("hello", 3); get_next ("hello", 4); get_next ("hello", 5);
(* Poly/ML output *)
... val it = (true, 1, #"h"): bool * int * char val it = (true, 2, #"e"): bool * int * char val it = (true, 3, #"l"): bool * int * char val it = (true, 4, #"l"): bool * int * char val it = (true, 5, #"o"): bool * int * char val it = (false, 5, #"^@"): bool * int * char