chicken-users
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]