Ch.6 SML# feature: direct interface to C

§ 6.3. Multiple argument functions and structs

In using C functions that takes multiple arguments or struct, the programmer should aware the following points.

  • Multiple argument functions
    C functions in general take multiple arguments. For example,libm library contains the following function to compute power.

    double pow(double x, double y);

    pow takes two parameters of type double and returns a value of type double. In SML#, this is declared by listing the argument types in parenthesis like C as follows.

    val C_pow = _import "pow" : (real, real) -> real

    Since the current version of SML# does not provide user defined multiple argument functions, SML# compiler converts this function to a function that takes a tuple of values. For the above declaration, SML# generates the following binding.

    val C_pow = _ : real * real -> real

    After this declaration, C_pow is used as a function to takes a pair as shown in the following.

    # val C_pow = _import "pow" : (real, real) -> real;
    val C_pow = _ : real * real -> real
    # val x = C_pow (2.0,3.0);
    val x = 8.0 : real
    # map C_pow [(1.0,2.0), (2.0,3.0), (3.0,4.0)];
    val it = [1.0, 8.0, 81.0] : real list
  • Struct argument
    As show in Table 6.1, a pointer to a struct in C corresponds to a record in SML#. For example,a C function

    struct S double x; double y;;
    int f(struct S* s);

    can be imported as:

    val f = _import : (real * real) -> int;

    This declaration yields the following binding.

    val f = _ : real * real -> real

    In this case, a record generated in SML# is directly passed to the C function. Since a record in SML# has the same memory layout as the corresponding struct in C, the passed record can be directly accessed by the C code. However, it should be noted that C is an imperative language that can mutate any memory contents. If C code mutates a record, then the original SML# record is mutated. Figure 6.2 show a simple example of passing a record to C.

    samle.c file:

    struct S {double X; double Y;};
         int f(struct S* s) {
         s->X = 2.0;
         return(s->X * s->Y);
    }

    sample.sml file:

    val f = _import "f" : real * real -> real
    val x = (1.1, 2.2);
    val y = f x;
    print ("The value of y:" R̂eal.toString y "̂\n");
    print ("The value of the first x:" R̂eal.toString (#1 x) "̂\n");

    Execution:

    # gcc -c sample.c
    # smlsharp sample.sml sample.o
    # a.out
    The value of y:4.4
    The value of the first x:2.0
    Figure 6.2. Passing a tuple to C function