Declaring functions with Racket's FFI is simple enough to do with _fun
and define-ffi-definer
. (A tutorial can be found on the PRL blog) For example, I can make a binding for atoi
:
#lang racket
(require ffi/unsafe
ffi/unsafe/define)
(define-ffi-definer define-libc #f)
(define-libc atoi (_fun _string -> _int))
And now I can call atoi
with Racket strings:
> (atoi "5")
5
The problem now is, how do I call C functions with a variable arity, such as printf
, who's signature is:
int printf(const char *format, ...);
I would guess that (since the linking happens dynamically), the Racket code should have a 'rest' argument at the end, which takes an array (pointer) for the rest of the arguments, that is either null terminated or (more likely), indicated by yet another argument. However, I can't think of any good ways to test this.
So, how do you handle variable arity functions with the Racket-C FFI?
答案 0 :(得分:3)
请查看此解决方案c-printf:
(provide c-printf)
(define interfaces (make-hash))
(define (c-printf fmt . args)
(define itypes
(cons _string
(map (lambda (x)
(cond [(and (integer? x) (exact? x)) _int]
[(and (number? x) (real? x)) _double*]
[(string? x) _string]
[(bytes? x) _bytes]
[(symbol? x) _symbol]
[else (error 'c-printf
"don't know how to deal with ~e" x)]))
args)))
(let ([printf (hash-ref interfaces itypes
(lambda ()
;; Note: throws away the return value of printf
(let ([i (get-ffi-obj "printf" #f
(_cprocedure itypes _void))])
(hash-set! interfaces itypes i)
i)))])
(apply printf fmt args)))