[ocaml-ctypes] Variadic Functions
Jeremy Yallop
yallop at gmail.com
Mon Oct 14 14:47:54 BST 2013
Hi Florian,
There are a few ways to approach this. I think my preferred approach
is to use string_opt, which maps OCaml's None to a null pointer. You
can then create null-terminated arrays pretty easily:
# Array.of_list string_opt [Some "foo"; Some "bar"; None];;
- : string option Array.t = { 0x27d8fc0, 0x27d9020, (nil) }
(There's a small pitfall with the string and string_opt types that you
may already be aware of: ctypes always passes a copy of OCaml strings
to C, so if the C code is writing to the strings then you should use
'char ptr' or some similar type instead.)
A slightly more raw approach, if you have an existing array of the
appropriate length, is to simply assign to the last element:
# a;;
- : int ptr Array.t = { 0x27d9f30, 0x27d9090 }
# a.(Array.length a - 1) <- from_voidp int null;;
- : unit = ()
# a;;
- : int ptr Array.t = { 0x27d9f30, (nil) }
Hope this helps,
Jeremy.
On 11 October 2013 17:07, Florian Pichlmeier
<florian.pichlmeier at mytum.de> wrote:
> Hi,
>
> thanks a lot for that quick response, it worked like a charm.
> The only problem now is that the other receive function expects
> the message to be null terminated. How do i get that with ctypes,
> that the last element in the array is NULL?
>
> Thanks again for your work,
>
> Florian
>
> Jeremy Yallop <yallop at gmail.com> wrote:
>
>
>> Hi Florian,
>>
>> The problem is the array argument; things should work better if you
>> change the binding to something like this:
>>
>> let stub = foreign "zstr_sendx_array"
>> ptr void @-> ptr string @-> size_t @-> returning int)
>>
>> You'll be able to call stub by passing 'Array.start c_array'.
>>
>> Kind regards,
>>
>> Jeremy.
>>
>> On 11 October 2013 15:46, Florian Pichlmeier
>> <florian.pichlmeier at mytum.de> wrote:
>>
>> > Hello Jeremy,
>> >
>> > i tried the approach with a more wrappable function.
>> >
>> > int
>> > zstr_sendx_array (void *socket, char **string, size_t nmsg)
>> > {
>> > zmsg_t *msg = zmsg_new ();
>> > for (size_t i=0;i<nmsg;i++) {
>> > zmsg_addstr (msg, *string);
>> > (*string)++;
>> > }
>> > return zmsg_send (&msg, socket);
>> > }
>> >
>> > and call it that
>> >
>> > let sendx socket msg_list =
>> > let c_array : string Ctypes.array = Array.of_list string msg_list
>> > in
>> > let stub = foreign "zstr_sendx_array"
>> > ((ptr void) @-> (array (List.length msg_list) string ) @-> size_t @-> returning int)
>> > in
>> > match stub socket c_array (Size_t.of_int(List.length msg_list))with
>> > | _ -> ()
>> >
>> > But i get this error
>> >
>> > Fatal error: exception Static.Unsupported("Unsupported argument type")
>> >
>> > Do you have an idea what my mistake is?
>> >
>> > Thank you.
>> >
>> > Florian
>> >
>> > Jeremy Yallop <yallop at gmail.com> wrote:
>> >
>> >
>> >
>> > > On 24 September 2013 12:43, Florian Pichlmeier
>> > > <florian.pichlmeier at mytum.de> wrote:
>> > >
>> > >
>> > > > Some of these functions are variadic functions, like this one
>> > > >
>> > > > // Create new poller
>> > > > CZMQ_EXPORT zpoller_t *
>> > > > zpoller_new (void *reader, ...);
>> > > >
>> > > > Is there a way with ctypes to emulate this signature?
>> > > >
>> > > >
>> > > >
>> > > >
>> > >
>> > > The short answer, unfortunately, is "no". This type of function is
>> > > rather tricky to wrap. This isn't due to a limitation of ctypes; it's
>> > > because there isn't a way to write wrappers for variadic functions in
>> > > standard C [0, 1]
>> > >
>> > > Ideally the C library interface should provide a more wrappable
>> > > interface in addition to the variadic function, e.g.
>> > >
>> > > zpoller_t *zpoller_new_vec(void **readers); /* argument is a
>> > > null-terminated array of pointers */
>> > >
>> > > or
>> > >
>> > > zpoller_t *zpoller_new_vec(void **readers, size_t nreaders);
>> > >
>> > > It might be worth sending a pull request to the czmq maintainers to
>> > > modify the interface.
>> > >
>> > > If you're not too concerned by portability you can use the fact that
>> > > some C implementations (e.g. GCC on Linux) have the same calling
>> > > convention for variadic and regular functions. Here ctypes offers an
>> > > advantage over handwritten bindings: since C types are exposed as
>> > > OCaml values you can construct a signature dynamically according to
>> > > the number of arguments you want to pass to the function. For
>> > > example, you might call the function using any of the signatures
>> > >
>> > > ptr void @-> returning (ptr (zpoller_t))
>> > >
>> > > ptr void @-> ptr void @-> returning (ptr (zpoller_t))
>> > >
>> > > ptr void @-> ptr void @-> ptr void @-> returning (ptr (zpoller_t))
>> > >
>> > > and so on. In fact, it ought to be possible (but probably not easy)
>> > > to write a function which accepts a list of pointers, constructs a
>> > > suitable signature for zpoller_new and calls the function.
>> > >
>> > > Jeremy.
>> > >
>> > > [0] http://c-faq.com/varargs/handoff.html
>> > > [1] http://c-faq.com/varargs/invvarargs.html
>> > >
>> > >
>> > >
>> > >
>> > >
>> >
>>
>>
More information about the Ctypes
mailing list