---
name: "callback"
section: "3"
platform: "linux"
package: "ffcall"
version: "2.5-1"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/callback/3"
---

# callback(3)

closures with variable arguments as first-class C functions

## NAME

callback - closures with variable arguments as first-class C functions

## SYNOPSIS

**#include \<callback.h\>**

```
void function (void* data, va_alist alist)
{
  va_start_type(alist[, return_type]);
  arg = va_arg_type(alist[, arg_type]);
  va_return_type(alist[[, return_type], return_value]);
}
```

*callback* **= alloc\_callback(***&function***,** *data***);**

**free\_callback(***callback***);**

```
is_callback(callback)
callback_address(callback)
callback_data(callback)
```

## DESCRIPTION

These functions implement *closures* with variable arguments as first-class C functions.

Closures as *first-class C functions* means that they fit into a function pointer and can be called exactly like any other C function. Moreover, they can be called with variable arguments and can return variable return values.

*callback* **= alloc\_callback(***&function***,** *data***)** allocates a callback. When *callback* gets called, it arranges to call *function*, passing *data* as first argument and, as second argument, the entire sequence of arguments passed to *callback*.

Function calling conventions differ considerably on different machines, therefore the arguments are accessed and the result value is stored through the same macros as used by the *vacall* package, see below.

The callbacks are functions with indefinite extent: *callback* is only deallocated when **free\_callback(***callback***)** is called.

**is\_callback(***callback***)** checks whether the C function *callback* was produced by a call to *alloc\_callback*. If this returns true, the arguments given to *alloc\_callback* can be retrieved:

**callback\_address(***callback***)** returns *&function*,

**callback\_data(***callback***)** returns *data*.

## VACALL MACROS

Within *function*, the following macros can be used to walk through the argument list and specify a return value:

- **va\_start\_***type***(***alist***\[,** *return\_type***\]);**

  starts the walk through the argument list and specifies the return type.

- *arg* **= va\_arg\_***type***(***alist***\[,** *arg\_type***\]);**

  fetches the next argument from the argument list.

- **va\_return\_***type***(***alist***\[\[,** *return\_type***\],** *return\_value***\]);**

  ends the walk through the argument list and specifies the return value.

The *type* in **va\_start\_***type* and **va\_return\_***type* shall be one of **void**, **int**, **uint**, **long**, **ulong**, **longlong**, **ulonglong**, **double**, **struct**, **ptr** or (for ANSI C calling conventions only) **char**, **schar**, **uchar**, **short**, **ushort**, **float**, depending on the class of *return\_type*.

The *type* specifiers in **va\_start\_***type* and **va\_return\_***type* must be the same. The *return\_type* specifiers passed to **va\_start\_***type* and **va\_return\_***type* must be the same.

The *type* in **va\_arg\_***type* shall be one of **int**, **uint**, **long**, **ulong**, **longlong**, **ulonglong**, **double**, **struct**, **ptr** or (for ANSI C calling conventions only) **char**, **schar**, **uchar**, **short**, **ushort**, **float**, depending on the class of *arg\_type*.

In **va\_start\_struct(***alist***,** *return\_type***,** *splittable***);** the *splittable* flag specifies whether the struct *return\_type* can be returned in registers such that every struct field fits entirely in a single register. This needs to be specified for structs of size 2\*sizeof(long). For structs of size \<= sizeof(long), *splittable* is ignored and assumed to be 1. For structs of size \> 2\*sizeof(long), *splittable* is ignored and assumed to be 0. There are some handy macros for this:

```
va_word_splittable_1 (type1)
va_word_splittable_2 (type1, type2)
va_word_splittable_3 (type1, type2, type3)
va_word_splittable_4 (type1, type2, type3, type4)
```

For a struct with three slots

```
struct { type1 id1; type2 id2; type3 id3; }
```

you can specify *splittable* as **va\_word\_splittable\_3 (***type1***,** *type2***,** *type3***)** .

## NOTES

Functions which want to emulate Kernighan & Ritchie style functions (i.e., in ANSI C, functions without a typed argument list) cannot use the *type* values **char**, **schar**, **uchar**, **short**, **ushort**, **float**. As prescribed by the default K&R C expression promotions, they have to use **int** instead of **char**, **schar**, **uchar**, **short**, **ushort** and **double** instead of **float**.

The macros **va\_start\_longlong()**, **va\_start\_ulonglong()**, **va\_return\_longlong()**, **va\_return\_ulonglong()**, **va\_arg\_longlong()** and **va\_arg\_ulonglong()** work only if the C compiler has a working **long long** 64-bit integer type.

The struct types used in **va\_start\_struct()** and **va\_struct()** must only contain (signed or unsigned) int, long, long long or pointer fields. Struct types containing (signed or unsigned) char, short, float, double or other structs are not supported.

## SEE ALSO

[**vacall**(3)](/vacall/3.md), [**trampoline**(3)](/trampoline/3.md).

## BUGS

The current implementations have been tested on a selection of common cases but there are probably still many bugs.

There are typically built-in limits on the size of the argument-list, which may also include the size of any structure arguments.

The decision whether a struct is to be returned in registers or in memory considers only the struct's size and alignment. This is inaccurate: for example, gcc on m68k-next returns **struct { char a,b,c; }** in registers and **struct { char a\[3\]; }** in memory, although both types have the same size and the same alignment.

The argument list can only be walked once.

## NON-BUGS

All information is passed in CPU registers and the stack. The **callback** package is therefore multithread-safe.

## PORTING

Porting **callback** consists in first porting the **vacall** and **trampoline** packages, then choosing a CPU register for passing the closure from **trampoline** to **vacall**. This register is normally the register designated by STATIC\_CHAIN\_REGNUM in the gcc source, file gcc-2.7.2/config/*cpu*/*cpu*.h.

## AUTHOR

Bruno Haible \<bruno@clisp.org\>

## ACKNOWLEDGEMENTS

Many ideas were cribbed from the gcc source.
