[racket] FFI question again - how to get a string back from C

From: Thomas Chust (chust at web.de)
Date: Sun Jun 12 06:02:40 EDT 2011

2011/6/12 keydana at gmx.de <keydana at gmx.de>:
> [...]
> In fact to be honest, I do not really understand the reason why I
> have to allocate a byte buffer here - what difference does it make
> to a char **, shouldn't both just be consecutive places in memory
> filled with ascii characters
> [...]

Hello Sigrid,

a byte buffer in Racket is something that C could see as a char *, a
char ** in C is something that Racket could see as a vector of byte
buffers — the second star adds a second level of indirection.

In terms of memory layout, a char * will be a pointer to a sequence of
byte sized objects while a char ** will be a pointer to a sequence of
word sized pointers, each pointing to a sequence of byte sized
objects.

On a sidenote, another level of indirection also tends to worsen
memory management headaches, because nothing guarantees that the
memory where the sequence of pointers is allocated and the memory
where those pointers' targets are living are related in any way.

> [...]
>> This wrapper function takes the date object and a format string as
>> arguments, allocates a buffer for the formatted result that is 128
>> bytes larger than the format string
>
> I had also hoped to do something like this, but then I realized that
> you can't conclude from the length of the format string on the
> length of the output, as the format strings might not be of the
> straightforward "yyyy-mm-dd" - like types, which I normally only
> tend to use :-;
> [...]

You could also add some flexibility by defaulting the buffer length to
some multiple or fixed offset of the format string but allowing the
user to optionally specify a different size — something like this may
work:

  (def-ocilib date->text OCI_DateToText
    (date fmt [size (+ (string-length fmt) 127)]) ::
    (date : _pointer) (fmt : _string)
    (size : _int)
    (str : _pointer = (malloc (add1 size) 'atomic)) ->
    (ok? : _bool) ->
    (and ok? (cast str _pointer _string)))

But if there is no sure way to guess the correct buffer size before
the function call, your only failsafe option is to invoke the function
repeatedly with increasing buffer sizes as long as it reports
failure. Of course, in this case you should somehow check whether the
function really failed due to space constraints or for some other
reason.

Ciao,
Thomas


-- 
When C++ is your hammer, every problem looks like your thumb.



Posted on the users mailing list.