Thread overview | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 20, 2014 Passing static array to C variadic function | ||||
---|---|---|---|---|
| ||||
Hi, I have a C variadic function (passed from C code into my D code via function pointer) that I need to call with a static array. So according to the D documentation, static arrays are passed by value in D2 and by reference in C and D1. (Even though http://dlang.org/abi.html claims "Static arrays are passed as pointers to their first element." - I guess this just wasn't updated for D2) For "normal" functions http://dlang.org/interfaceToC.html tells me to add a "ref" in the function signature, to tell D to pass it by reference (couldn't this be implicit for extern (C) functions?) - But I obviously can't to this for vararg function arguments. So let's imagine the following code: extern (C) alias funPtr_t = ptrdiff_t function( ptrdiff_t arg, ... ); funPtr_t fun = ...; // is assigned somewhere.. void bla( float[3] v ) { fun( 42, v ); } This produces the following compiler error (DMD 2.065 linux amd64): "Error: cannot pass static arrays to extern(C) vararg functions" /However/, if I typedef a float[3] type, the compiler does not complain (not sure if the code behaves like expected, though, or if it's still passed by value instead of by reference as expected by the C code): typedef float[3] vec3_t; void bla( vec3_t v ) { fun( 42, v ); } Then again, if I use alias instead of the deprecated typedef: alias vec3_t = float[3]; I again get "Error: cannot pass static arrays to extern(C) vararg functions". Is there a "proper" way to make this work? If not, any ideas for a viable workaround? Cheers, Daniel |
July 20, 2014 Re: Passing static array to C variadic function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Gibson | On Sunday, 20 July 2014 at 16:00:41 UTC, Daniel Gibson wrote:
> Hi,
> I have a C variadic function (passed from C code into my D code via function pointer) that I need to call with a static array.
>
> So according to the D documentation, static arrays are passed by value in D2 and by reference in C and D1.
> (Even though http://dlang.org/abi.html claims "Static arrays are passed as pointers to their first element." - I guess this just wasn't updated for D2)
>
> For "normal" functions http://dlang.org/interfaceToC.html tells me to add a "ref" in the function signature, to tell D to pass it by reference (couldn't this be implicit for extern (C) functions?) - But I obviously can't to this for vararg function arguments.
>
> So let's imagine the following code:
>
> extern (C) alias funPtr_t = ptrdiff_t function( ptrdiff_t arg, ... );
>
> funPtr_t fun = ...; // is assigned somewhere..
>
> void bla( float[3] v ) {
> fun( 42, v );
> }
>
> This produces the following compiler error (DMD 2.065 linux amd64):
> "Error: cannot pass static arrays to extern(C) vararg functions"
>
> /However/, if I typedef a float[3] type, the compiler does not complain (not sure if the code behaves like expected, though, or if it's still passed by value instead of by reference as expected by the C code):
>
> typedef float[3] vec3_t;
>
> void bla( vec3_t v ) {
> fun( 42, v );
> }
>
> Then again, if I use alias instead of the deprecated typedef:
> alias vec3_t = float[3];
> I again get "Error: cannot pass static arrays to extern(C) vararg functions".
>
>
> Is there a "proper" way to make this work?
> If not, any ideas for a viable workaround?
>
> Cheers,
> Daniel
C functions takes arrays by pointer to first element. fun(42, v.ptr) should work.
|
July 20, 2014 Re: Passing static array to C variadic function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Gibson | Daniel Gibson:
> For "normal" functions http://dlang.org/interfaceToC.html tells me to add a "ref" in the function signature, to tell D to pass it by reference (couldn't this be implicit for extern (C) functions?)
I don't know why D isn't adapting such things to the needs of C.
Bye,
bearophile
|
July 20, 2014 Re: Passing static array to C variadic function | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | Am 20.07.2014 18:37, schrieb bearophile:
> Daniel Gibson:
>
>> For "normal" functions http://dlang.org/interfaceToC.html tells me to
>> add a "ref" in the function signature, to tell D to pass it by
>> reference (couldn't this be implicit for extern (C) functions?)
>
> I don't know why D isn't adapting such things to the needs of C.
>
> Bye,
> bearophile
Yeah, IMHO it would indeed make sense to make extern (C) functions behave more like C.
They already are different to D functions (different name mangling and, more visibly to the user, varargs behave differently), so why not do it properly?
As far as I see it, passing static arrays by value to C functions is never what you want because C just doesn't support it, so why not make it implicit? This also goes the other way round: if I implement an extern (C) function in D (vs just having a function pointer or a declaration of a function implemented in C), D "thinks" it's getting a static array by value when it's really just getting a ref..
And for the varargs case (where I can't just add "ref"), it's totally non-obvious that I have to pass staticArr.ptr instead, so here it would be even more desirable to have that done implicitly.
So what I (naive as I am) would expect extern (C) to do to functions is:
* C name mangling (that's done)
* C-style varargs (also done)
* passing stuff to the function is done as C expects it (not done,
also: are there other cases than the static array one that are
different?)
* Disallowing template arguments (because how would I declare and call
that function in C?) (not done)
* /Maybe/ disallowing types as arguments/return types that are not
supported by C (D classes; not done)?
(OTOH, one the C side one could just handle them as void* and pass
instances around opaquely)
Cheers,
Daniel
|
July 21, 2014 Re: Passing static array to C variadic function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Gibson | "Daniel Gibson" wrote in message news:lqh3vb$c2b$1@digitalmars.com... > * passing stuff to the function is done as C expects it (not done, > also: are there other cases than the static array one that are > different?) Dynamic arrays. D used to allow passing static and dynamic arrays to C varargs with no problems. This lead to nasty segfaults, especially with this code: printf("Hello %s\n", "segfault"); which looks perfectly valid in D but certainly isn't. What you actually meant to pass is up to you to specify. It would not make a lot of sense for C functions to have a different set of implicit conversion rules to other functions. > * Disallowing template arguments (because how would I declare and call > that function in C?) (not done) This is probably worth reporting, I doubt it works correctly. > * /Maybe/ disallowing types as arguments/return types that are not > supported by C (D classes; not done)? > (OTOH, one the C side one could just handle them as void* and pass > instances around opaquely) Yes, this is why they are not disallowed. This is just too damn useful. printf("Pointer: %p\n", new Class()); |
July 22, 2014 Re: Passing static array to C variadic function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Murphy | Am 21.07.2014 06:07, schrieb Daniel Murphy: > > > "Daniel Gibson" wrote in message news:lqh3vb$c2b$1@digitalmars.com... > >> * passing stuff to the function is done as C expects it (not done, >> also: are there other cases than the static array one that are >> different?) > > Dynamic arrays. > > D used to allow passing static and dynamic arrays to C varargs with no > problems. This lead to nasty segfaults, especially with this code: > > printf("Hello %s\n", "segfault"); If the compiler did the right thing for extern (C) functions (i.e. implicitly passing "segfault" by reference), this shouldn't cause a segfault. > > which looks perfectly valid in D but certainly isn't. What you actually > meant to pass is up to you to specify. It would not make a lot of sense > for C functions to have a different set of implicit conversion rules to > other functions. > >> * Disallowing template arguments (because how would I declare and call >> that function in C?) (not done) > > This is probably worth reporting, I doubt it works correctly. > >> * /Maybe/ disallowing types as arguments/return types that are not >> supported by C (D classes; not done)? >> (OTOH, one the C side one could just handle them as void* and pass >> instances around opaquely) > > Yes, this is why they are not disallowed. This is just too damn useful. > > printf("Pointer: %p\n", new Class()); Well, that printf("%s", "asdf"); doesn't work (really?) and that I have to pass static arrays arr.ptr in varargs, is much more surprising/unexpected than having to casts class objects to void* when passing them to a C function. But still, it probably is useful to have type checking on the D side even when just treating them as void* on the C side. Cheers, Daniel |
July 22, 2014 Re: Passing static array to C variadic function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Gibson | "Daniel Gibson" wrote in message news:lql6ec$1rqk$1@digitalmars.com... > > > > printf("Hello %s\n", "segfault"); > > If the compiler did the right thing for extern (C) functions (i.e. implicitly passing "segfault" by reference), this shouldn't cause a segfault. Whether or not passing the point to the C function is the right thing depends on your perspective. Old D code (from the 32-bit only days) used to do this successfully: printf("Hello %.*s\n", "segfault"); So it relied on both the length and pointer being passed. Unfortunately this was done quite a lot, so simply changing the rules so string literals get passed to C varargs as pointers would silently (and horribly) break this code. Giving an error and forcing you to be explicit about what exactly you wanted is the best that's possible. > Well, that printf("%s", "asdf"); doesn't work (really?) and that I have to pass static arrays arr.ptr in varargs, is much more surprising/unexpected than having to casts class objects to void* when passing them to a C function. That is an error because it was causing bugs, usually when porting C++ code which looks exactly the same. I've never seen a bug with passing a class handle to printf. |
July 22, 2014 Re: Passing static array to C variadic function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Murphy | Daniel Murphy:
> Giving an error and forcing you to be explicit about what exactly you wanted is the best that's possible.
OK. This is far better than silent bugs :-)
Bye,
bearophile
|
July 22, 2014 Re: Passing static array to C variadic function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Murphy | Am 22.07.2014 11:01, schrieb Daniel Murphy:
>
> Old D code (from the 32-bit only days) used to do this successfully:
>
> printf("Hello %.*s\n", "segfault");
>
> So it relied on both the length and pointer being passed. Unfortunately
> this was done quite a lot, so simply changing the rules so string
> literals get passed to C varargs as pointers would silently (and
> horribly) break this code.
ok, I didn't know about that hack.. which shouldn't have been used in the first place :-P
So at least for strings it kinda makes sense.. and if strings are considered char arrays (isn't there a proper string type in D2?) for consistency it should be the same for other arrays.
Maybe at least the "Interfacing to C" and/or "C-style Variadic Functions" documentation could supply a bit more information about how to pass arrays and especially static arrays as vararg.
Anyway, thanks for the clarification!
Cheers,
Daniel
|
July 22, 2014 Re: Passing static array to C variadic function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Gibson | On Tuesday, 22 July 2014 at 13:28:27 UTC, Daniel Gibson wrote: > Am 22.07.2014 11:01, schrieb Daniel Murphy: >> >> Old D code (from the 32-bit only days) used to do this successfully: >> >> printf("Hello %.*s\n", "segfault"); >> >> So it relied on both the length and pointer being passed. Unfortunately >> this was done quite a lot, so simply changing the rules so string >> literals get passed to C varargs as pointers would silently (and >> horribly) break this code. > (isn't there a proper string type in D2?) nope, it's just an ordinary slice (although the fact that it's a slice of char does make it a bit special w.r.t. unicode) The compiler doesn't even know about the name string, it's just defined here: https://github.com/D-Programming-Language/druntime/blob/master/src/object.di#L28 |
Copyright © 1999-2021 by the D Language Foundation