[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Chicken-users] FFI with callbacks for gnu readline
From: |
Thomas Chust |
Subject: |
Re: [Chicken-users] FFI with callbacks for gnu readline |
Date: |
Thu, 19 Jan 2006 10:43:14 +0000 (GMT) |
On Wed, 18 Jan 2006, LeviPearson wrote:
[...] I previously had scheme_completion return a c-string, and I
assumed it would somehow generate a correctly null-terminated string.
It did in most cases, but occasionally there was a garbage character
afterward. If I did a (print) of the value I was about to return in
scheme_completion and a printf() in completion_func() right after it was
returned, I saw the garbage character appear between the two. I don't
think garbage collection could account for that. [...]
Oops, you're quite right, I can reproduce it with a simple test program
like that one:
(define-external (blubb) c-string
(print (string-copy "bla")))
(define my-puts
(foreign-safe-lambda* void ()
"puts(blubb());"))
(do ((i 0 (add1 i))) ((> i 10000) (void))
(my-puts))
And indeed the compiler generates a
return C_string_or_null(C_callback_wrapper((void *)f_20,0));
in the wrapper for blubb. The function C_string_or_null is defined in
runtime.c and does a
return C_truep(x) ? C_c_string(x) : NULL;
while C_c_string is defined as a macro in chicken.h and just extracts the
data pointer from a string object.
I think the reason why you don't get a zero terminated string by default,
is that it would always have to be freshly allocated -- and then the
question is when it should be freed or whether that should be left to the
C code getting the string back.
There are basically two solutions that come to my mind, which use
Scheme only instead of a C helper. In your case you need a statically
allocated string, so you could replace my oversimplified example by
something like this:
(use lolevel)
(define-external (blubb) c-pointer
(let* ((s "bla")
(l (string-length s))
(p (allocate (fx+ (string-length s) 1))))
(print s)
(move-memory! s p l)
(move-memory! "\x00" (pointer-offset p l) 1)
p))
(define my-puts
(foreign-safe-lambda* void ()
"char *s = blubb();"
"puts(s);"
"free(s);"))
(do ((i 0 (add1 i))) ((> i 10000) (void))
(my-puts))
If you wouldn't need the string that is returned to be releasable by free,
you could also do the more elegant
(define-external (blubb) c-string
(print (string-append "bla" "\x00")))
(define my-puts
(foreign-safe-lambda* void ()
"puts(blubb());"))
(do ((i 0 (add1 i))) ((> i 10000) (void))
(my-puts))
though.
cu,
Thomas