Skip to content

Instantly share code, notes, and snippets.

@posborne
Created February 17, 2015 04:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save posborne/063752d7e39211f987bd to your computer and use it in GitHub Desktop.
Save posborne/063752d7e39211f987bd to your computer and use it in GitHub Desktop.
Closures in C using libffi closures API
#include <stdio.h>
#include <ffi.h>
#include <stdlib.h>
/* Acts like puts with the file given at time of enclosure. */
void puts_binding(ffi_cif *cif, void *ret, void* args[], void *stream) {
*(ffi_arg *) ret = fputs(*(char **) args[0], (FILE *) stream);
}
typedef int (*puts_t)(char *);
typedef struct {
ffi_closure* closure;
ffi_type *arg_types[1];
ffi_cif cif;
puts_t fn;
} ffi_putter_t;
ffi_putter_t*
make_putter(FILE* stream) {
ffi_status status;
void *code_ptr;
ffi_putter_t *ffi_putter;
ffi_putter = malloc(sizeof(*ffi_putter));
ffi_putter->closure = ffi_closure_alloc(sizeof(ffi_closure), &code_ptr);
if (ffi_putter == NULL) {
printf("Failed to allocated memory for closure!\n");
goto err;
}
ffi_putter->arg_types[0] = &ffi_type_pointer;
status = ffi_prep_cif(&(ffi_putter->cif), FFI_DEFAULT_ABI, 1, &ffi_type_sint, ffi_putter->arg_types);
if (status != FFI_OK) {
printf("ffi_prep_cif failed: %d\n", status);
goto err;
}
status = ffi_prep_closure_loc(ffi_putter->closure, &(ffi_putter->cif), puts_binding, stream, code_ptr);
if (status != FFI_OK) {
printf("ffi_prep_closure_loc failed: %d\n", status);
goto err;
}
ffi_putter->fn = (puts_t)code_ptr;
return ffi_putter;
err:
ffi_closure_free(ffi_putter->closure);
free(ffi_putter);
return NULL;
}
int main() {
ffi_putter_t *stdio_putter;
ffi_putter_t *stderr_putter;
stdio_putter = make_putter(stdout);
stderr_putter = make_putter(stderr);
stderr_putter->fn("Writing to STDERR\n");
stdio_putter->fn("Writing to STDOUT\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment