Interface to C (The GNU Modula-2 Compiler)

### 2.17 Interfacing GNU Modula-2 to C ¶

The GNU Modula-2 compiler tries to use the C calling convention wherever possible however some parameters have no C equivalent and thus a language specific method is used. For example unbounded arrays are passed as a `struct {void *address, unsigned int high}` and the contents of these arrays are copied by callee functions when they are declared as non `VAR` parameters. The `VAR` equivalent unbounded array parameters need no copy, but still use the `struct` representation.

The recommended method of interfacing GNU Modula-2 to C is by telling the definition module that the implementation is in the C language. This is achieved by using the tokens `DEFINITION MODULE FOR "C"`. Here is an example `libprintf.def`.

    DEFINITION MODULE FOR "C" libprintf ;

    EXPORT UNQUALIFIED printf ;

    PROCEDURE printf (a: ARRAY OF CHAR; ...) : [ INTEGER ] ;

    END libprintf.

the `UNQUALIFIED` keyword in the definition module informs GNU Modula-2 not to prefix the module name to exported references in the object file.

The `printf` declaration states that the first parameter semantically matches `ARRAY OF CHAR` but since the module is for the C language it will be mapped onto `char *`. The token `...` indicates a variable number of arguments (varargs) and all parameters passed here are mapped onto their C equivalents. Arrays and constant strings are passed as pointers. Lastly `[ INTEGER ]` states that the caller can ignore the function return result if desired.

The hello world program can be rewritten as:

    MODULE hello ;

    FROM libprintf IMPORT printf ;

    BEGIN
       printf ("hello world\n")
    END hello.

and it can be compiled by:

‘`gm2 -g hello.mod -lc`’

In reality the ‘`-lc`’ is redundant as libc is always included in the linking process. It is shown here to emphasize that the C library or object file containing `printf` must be present. The search path for modules can be changed by using ‘`-I`’.

If a procedure function is declared using varargs then some parameter values are converted. The table below summarizes the default conversions and default types used.

    Actual Parameter       |  Default conversion  |   Type of actual
                           |                      |   value passed
    ===============================================================
    123                    |  none                |   long long int
    "hello world"          |  none                |   const char *
    a: ARRAY OF CHAR       |  ADR (a)             |   char *
    a: ARRAY [0..5] OF CHAR|  ADR (a)             |   char *
    3.14                   |  none                |   long double

If you wish to pass `int` values then you should explicitly convert the constants using one of the conversion mechanisms. For example: `INTEGER(10)` or `VAL(INTEGER, 10)` or `CAST(INTEGER, 10)`.