6.32.3 Declaring C Functions

Before you can call lseek or dlseek, you have to declare it.

In Gforth 1.0, C function declarations have to be enclosed in a C library definition (see Defining library interfaces), e.g.

c-library lseek-lib
...
end-c-library

The declaration of a C function consists of two parts:

The C part

is the C declaration of the function, or more typically and portably, a C-style #include of a file that contains the declaration of the C function.

The Forth part

declares the Forth types of the parameters and the Forth word name corresponding to the C function.

For the words lseek and dlseek mentioned earlier, the declarations are:

c-library lseek-lib
\c #define _FILE_OFFSET_BITS 64
\c #include <sys/types.h>
\c #include <unistd.h>
c-function lseek lseek n n n -- n
c-function dlseek lseek n d n -- d
0 constant SEEK_SET \ getting the value from the .h files is complicated
end-c-library

The C part of the declarations is prefixed by \c, and the rest of the line is ordinary C code. You can use as many lines of C declarations as you like, and they are visible for all further function declarations.

The Forth part declares each interface word with c-function, followed by the Forth name of the word, the C name of the called function, and the stack effect of the word. The stack effect contains an arbitrary number of types of parameters, then --, and then exactly one type for the return value. The possible types are:

n

single-cell signed integer

u

single-cell unsigned integer

a

address (single-cell)

d

double-cell signed integer

ud

double-cell unsigned integer

r

floating-point value

func

C function pointer

void

no value (used as return type for void functions)

s

String: On the Forth side, represented as c-addr u pair, on the C side represented as zero-terminated string.

ws

wide string: On the Forth side, represented as c-addr u pair describing an UTF-8 string; on the C side, represented as a zero-terminated string of wchar_t (i.e., UTF-16 or UTF-32, depending on the platform).

t

tuple

0

NULL pointer (sentinel)

...

varargs (programmable)

To deal with variadic C functions, you can declare one Forth word for every pattern you want to use, e.g.:

\c #include <stdio.h>
c-function printf-nr printf s n r -- n
c-function printf-rn printf s r n -- n

Note that with C functions declared as variadic (or if you don’t provide a prototype), the C interface has no C type to convert to, so no automatic conversion happens, which may lead to portability problems in some cases. You can add the C type cast in curly braces after the Forth type. This also allows to pass e.g. structs to C functions, which in Forth cannot live on the stack.

c-function printfll printf s n{(long long)} -- n
c-function pass-struct pass_struct a{*(struct foo *)} -- n

This typecasting is not available to return values, as C does not allow typecasts for lvalues.

\c ( "rest-of-line" –  ) gforth-0.7 “backslash-c”

One line of C declarations for the C interface

c-function ( "forth-name" "c-name" "{type}" "—" "type" –  ) gforth-0.7

Define a Forth word forth-name. Forth-name has the specified stack effect and calls the C function c-name.

c-value ( "forth-name" "c-name" "—" "type" –  ) gforth-1.0

Define a Forth word forth-name. Forth-name has the specified stack effect and gives the C value of c-name.

c-variable ( "forth-name" "c-name" –  ) gforth-1.0

Define a Forth word forth-name. Forth-name returns the address of c-name.

In order to work, this C interface invokes GCC at run-time and uses dynamic linking. If these features are not available, there are other, less convenient and less portable C interfaces in lib.fs and oldlib.fs. These interfaces are mostly undocumented and mostly incompatible with each other and with the documented C interface; you can find some examples for the lib.fs interface in lib.fs.