Help with basic ffi and define-external callback

Paul Wisehart via Chicken-users <[email protected]> Fri, 10 Apr 2026 18:03:52 -0400
Newsgroups gmane.lisp.scheme.chicken
Message-ID <[email protected]>
Hi!

I have been using basic ffi successfully.

Now I am trying to level up and call a scheme
defined function from C.

I am looking here:

https://wiki.call-cc.org/man/5/Module%20(chicken%20foreign)#callbacks

I set up a basic example here:

https://codeberg.org/pkw/chicken-learn/src/branch/main/c-callbacks

-------------

I am trying it in two ways and they both fail with:

home:~/code/scm/learn/c-callbacks$ ./main.exe  fn1
fn1

Error: (location) bad argument type - locative cannot refer to objects of this type: #<procedure (interface#cb2)>      

        Call history:

        main.scm:1: chicken.load#load-extension
        main.scm:1: chicken.load#load-extension
        main.scm:1: chicken.load#load-extension
        interface.scm:6: chicken.load#load-extension
        main.scm:24: main
        main.scm:15: chicken.process-context#command-line-arguments
        main.scm:17: scheme#display
        main.scm:18: ##sys#check-output-port
        main.scm:18: ##sys#print
        main.scm:18: ##sys#make-locative   

-------------

My scheme code looks like:

(define-external (cb1) void (display "cb1\n"))
(define-external (cb2) int 99)

(define-external (cstrl (c-string x)) int (string-length x))

(define fn1
  (foreign-safe-lambda
    int
    "fn1"
    int
    c-pointer))

(define fn2
  (foreign-safe-lambda
    void
    "fn2"
    int
    c-pointer))

-------------

My C code looks like: (i have a header file with the same signatures
but no var names on the definitions.)

#include "cinterface.h"

void
_f(void)
{
        printf("_f\n");
}

int
fn1(int i, int ifn(int))
{
        /* call a function pointer as a sanity check */
        void (*f)(void);
        f = _f;
        f();

        printf("fn1 i:%d\n", i);
        return 66 + i;
}

void
fn2(int n, void (*f)(void))
{
        (void) f;
        printf("fn2 n:%d\n", n);
}

-------------

(define (usage)
  (display "main.exe [fn1 fn2]\n"))

(define (main)
  (match (command-line-arguments)
    (("fn1")
      (display "fn1\n")
      (printf "fn1:~a~%" (interface:fn1 7 #$interface:cb2)))
    (("fn2")
      (display "fn2\n")
      (interface:fn2 23 #$interface:cb1))
    (_ (usage))))

(main)

-------------

Any ideas?
I am happy to try something or maybe if
this isn't clear I can try to say it differently.

Thanks!
--
Paul W