www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Passing ref T[n] to C

reply Mike Parker <aldacron gmail.com> writes:
Given the following declarations in C:

typedef int foo_t[3];
void take_foo( foo_t );

How would you handle this in D?

It's obvious to me that the type should be declared the same way, so 
that it may be used the same way in D as in C:

alias foo_t = int[3];

Given that on the C side, foo_t[3] parameters will degrade to pointers, 
it's just as obvious to me to declare the function on the D side like so:

extern( C ) void take_foo( foo_t* );

That means that one need pass foo.ptr when calling the function, but it 
doesn't really bother me. However, it was recently brought to my 
attention that the following actually works:

extern( C ) void take_foo( ref foo_t );

foo_t foo = [1, 2, 3];
void take_foo( foo );

I tested it with DMC and DMD and it actually worked fine. I was 
expecting the length field to get in the way, but it didn't seem to. I 
was able to print the values of the array just fine on the C side.

My question is, can I rely on this? Is there a guarantee that a ref 
static array parameter will be compatible with a C array pointer on 
every platform and architecture? A voice in my head is screaming NO at 
me in all caps and with multiple exclamation points. But, if true, it 
would certainly simplify user code by not having to remember to pass 
foo.ptr all the time. So I thought I'd ask. I can't find anything 
regarding the implementation details of ref parameters.
Dec 09 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Mike Parker:

 I was  expecting the length field to get in the way, but it
 didn't seem to.
If you pass a fixed-sized array by ref it only passes the pointer. The length is not passed, it's a compile-time known value.
 My question is, can I rely on this? Is there a guarantee that a 
 ref static array parameter will be compatible with a C array 
 pointer on every platform and architecture?
While the semantics of "ref" if fixed, I don't remember if the standard D ABI specifies how "fixed-sized array by ref" is implemented. Bye, bearophile
Dec 09 2013
prev sibling parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Monday, 9 December 2013 at 15:46:40 UTC, Mike Parker wrote:
 Given that on the C side, foo_t[3] parameters will degrade to 
 pointers, it's just as obvious to me to declare the function on 
 the D side like so:

 extern( C ) void take_foo( foo_t* );

 That means that one need pass foo.ptr when calling the 
 function, but it doesn't really bother me.
Do you mean `&foo`? While they both yield the same memory address, the type of the pointer is different. `foo.ptr` is typed as a pointer to the element type, while `&foo` is (completely regularly) typed as a pointer to the fixed-length array. i.e. `T*` vs `T[n]*` where T is the element type of the array.
 However, it was recently brought to my attention that the
 following actually works:

 extern( C ) void take_foo( ref foo_t );

 foo_t foo = [1, 2, 3];
 void take_foo( foo );

 I tested it with DMC and DMD and it actually worked fine. I was 
 expecting the length field to get in the way, but it didn't 
 seem to. I was able to print the values of the array just fine 
 on the C side.
Fixed-length arrays in D have no data-field for the length, because the length is always known at compile-time. ABI-wise, `int[3]` is always just 3 contiguous `int`s in memory. They are very unlike slices.
 My question is, can I rely on this? Is there a guarantee that a 
 ref static array parameter will be compatible with a C array 
 pointer on every platform and architecture? A voice in my head 
 is screaming NO at me in all caps and with multiple exclamation 
 points. But, if true, it would certainly simplify user code by 
 not having to remember to pass foo.ptr all the time. So I 
 thought I'd ask. I can't find anything regarding the 
 implementation details of ref parameters.
Upon consulting the specification[1], it looks like it's officially recommended to use `ref T[n]` for C's `T[n]`, and `T*` for C's `T[]`, in parameter lists. [1] http://dlang.org/interfaceToC.html, "Passing D Array Arguments to C Functions"
Dec 09 2013
next sibling parent "Mike Parker" <aldacron gmail.com> writes:
On Monday, 9 December 2013 at 16:11:39 UTC, Jakob Ovrum wrote:
 Upon consulting the specification[1], it looks like it's 
 officially recommended to use `ref T[n]` for C's `T[n]`, and 
 `T*` for C's `T[]`, in parameter lists.

 [1] http://dlang.org/interfaceToC.html, "Passing D Array 
 Arguments to C Functions"
Thanks. I completely missed that.
Dec 09 2013
prev sibling parent "Mike Parker" <aldacron gmail.com> writes:
On Monday, 9 December 2013 at 16:11:39 UTC, Jakob Ovrum wrote:
 On Monday, 9 December 2013 at 15:46:40 UTC, Mike Parker wrote:
 Given that on the C side, foo_t[3] parameters will degrade to 
 pointers, it's just as obvious to me to declare the function 
 on the D side like so:

 extern( C ) void take_foo( foo_t* );

 That means that one need pass foo.ptr when calling the 
 function, but it doesn't really bother me.
Do you mean `&foo`?
Actually, I meant to declare the parameter as int*.
Dec 09 2013