Next: , Up: Interfacing with C   [Contents]


15.10.1.1 Using pragma foreign_type for C

A C ‘pragma foreign_type’ declaration has the form:

:- pragma foreign_type("C", MercuryTypeName, "CForeignType").

For example,

:- pragma foreign_type("C", long_double, "long double").

The CForeignType can be any C type name that obeys the following restrictions. Function types, array types, and incomplete types are not allowed. The type name must be such that when declaring a variable in C of that type, no part of the type name is required after the variable name. (This rule prohibits, for example, function pointer types such as ‘void (*)(void)’; however, it would be OK to use a typedef name which was defined as a function pointer type.)

C preprocessor directives (such as ‘#if’) may not be used in CForeignType. (You can however use a typedef name that refers to a type defined in a ‘pragma foreign_decl’ declaration, and the ‘pragma foreign_decl’ declaration may contain C preprocessor directives.)

If the MercuryTypeName is the type of a parameter of a procedure defined using ‘pragma foreign_proc’, it will be passed to the foreign_proc’s foreign language code as CForeignType.

Furthermore, any Mercury procedure exported with ‘pragma foreign_export’ will use CForeignType as the type for any parameters whose Mercury type is MercuryTypeName.

The builtin Mercury type c_pointer may be used to pass C pointers between C functions which are called from Mercury. For example:

:- module pointer_example.
:- interface.

:- type complicated_c_structure.

% Initialise the abstract C structure that we pass around in Mercury.
:- pred initialise_complicated_structure(complicated_c_structure::uo) is det.

% Perform a calculation on the C structure.
:- pred do_calculation(int::in, complicated_c_structure::di,
        complicated_c_structure::uo) is det.

:- implementation.

% Our C structure is implemented as a c_pointer.
:- type complicated_c_structure
    --->    complicated_c_structure(c_pointer).

:- pragma foreign_decl("C",
   extern struct foo *init_struct(void);
   extern struct foo *perform_calculation(int, struct foo *);
");

:- pragma foreign_proc("C",
    initialise_complicated_structure(Structure::uo),
    [will_not_call_mercury, may_call_mercury],
"
    Structure = init_struct();
").

:- pragma foreign_proc("C",
    do_calculation(Value::in, Structure0::di, Structure::uo),
    [will_not_call_mercury, may_call_mercury],
"
    Structure = perform_calculation(Value, Structure0);
").

We strongly recommend the use of ‘pragma foreign_type’ instead of c_pointer as the use of ‘pragma foreign_type’ results in more type-safe code.


Next: , Up: Interfacing with C   [Contents]