www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Passing static arrays to C

reply "Jakob Bornecrantz" <wallbraker gmail.com> writes:
Hey everybody.

How are you supposed to pass static arrays to C functions? I'm 
asking because I'm getting conflicting info from how DMD works 
and on IRC.

The below example prints:
test1 0x7fff857c1db0
test2 0x7fff857c1db0
test3 (nil)
test4 0x7fff857c1db0


D:
void main()
{
         float[3] arr;
         test1(arr);
         test2(&arr[0]);
         test3(0, arr);
         test4(0, &arr[0]);
}

extern(C):
void test1(float[3] arr);
void test2(float *arr);
void test3(int, float[3] arr);
void test4(int, float *arr);


C:
#include <stdio.h>

void test1(float arr[3]) { printf("test1 %p\n", &arr[0]); }
void test2(float arr[3]) { printf("test2 %p\n", &arr[0]); }
void test3(int anything, float arr[3]) { printf("test3 %p\n", 
&arr[0]); }
void test4(int anything, float arr[3]) { printf("test4 %p\n", 
&arr[0]); }

Comments please.

Cheers, Jakob.
Oct 24 2012
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-10-24 09:54, Jakob Bornecrantz wrote:
 Hey everybody.

 How are you supposed to pass static arrays to C functions? I'm asking
 because I'm getting conflicting info from how DMD works and on IRC.

 The below example prints:
 test1 0x7fff857c1db0
 test2 0x7fff857c1db0
 test3 (nil)
 test4 0x7fff857c1db0


 D:
 void main()
 {
          float[3] arr;
          test1(arr);
          test2(&arr[0]);
          test3(0, arr);
          test4(0, &arr[0]);
 }

 extern(C):
 void test1(float[3] arr);
 void test2(float *arr);
 void test3(int, float[3] arr);
 void test4(int, float *arr);


 C:
 #include <stdio.h>

 void test1(float arr[3]) { printf("test1 %p\n", &arr[0]); }
 void test2(float arr[3]) { printf("test2 %p\n", &arr[0]); }
 void test3(int anything, float arr[3]) { printf("test3 %p\n", &arr[0]); }
 void test4(int anything, float arr[3]) { printf("test4 %p\n", &arr[0]); }

That seems weird. Since static arrays are passed by value in D you need to send a reference: extern (C) void test1(ref float[3] arr); float[3] arr; test1(arr); BTW, do not ever use "&arr[0]", use "arr.ptr" instead to get the pointer of the array. http://dlang.org/interfaceToC.html Search for "Passing D Array Arguments to C Functions". -- /Jacob Carlborg
Oct 24 2012
parent reply "Jakob Bornecrantz" <wallbraker gmail.com> writes:
On Wednesday, 24 October 2012 at 09:03:25 UTC, Jacob Carlborg 
wrote:
 On 2012-10-24 09:54, Jakob Bornecrantz wrote:
 Hey everybody.

 How are you supposed to pass static arrays to C functions? I'm 
 asking
 because I'm getting conflicting info from how DMD works and on 
 IRC.

 The below example prints:
 test1 0x7fff857c1db0
 test2 0x7fff857c1db0
 test3 (nil)
 test4 0x7fff857c1db0


 D:
 void main()
 {
         float[3] arr;
         test1(arr);
         test2(&arr[0]);
         test3(0, arr);
         test4(0, &arr[0]);
 }

 extern(C):
 void test1(float[3] arr);
 void test2(float *arr);
 void test3(int, float[3] arr);
 void test4(int, float *arr);


 C:
 #include <stdio.h>

 void test1(float arr[3]) { printf("test1 %p\n", &arr[0]); }
 void test2(float arr[3]) { printf("test2 %p\n", &arr[0]); }
 void test3(int anything, float arr[3]) { printf("test3 %p\n", 
 &arr[0]); }
 void test4(int anything, float arr[3]) { printf("test4 %p\n", 
 &arr[0]); }

That seems weird. Since static arrays are passed by value in D you need to send a reference:

Yeah I'm wondering if this isn't a bug.
 extern (C) void test1(ref float[3] arr);

 float[3] arr;
 test1(arr);

 BTW, do not ever use "&arr[0]", use "arr.ptr" instead to get 
 the pointer of the array.

Right you are, thats what you get when mixing C and D code.
 http://dlang.org/interfaceToC.html

 Search for "Passing D Array Arguments to C Functions".

Thanks for the info. Cheers, Jakob.
Oct 24 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/24/2012 2:55 AM, Jakob Bornecrantz wrote:
 On Wednesday, 24 October 2012 at 09:03:25 UTC, Jacob Carlborg wrote:
 On 2012-10-24 09:54, Jakob Bornecrantz wrote:
 Hey everybody.

 How are you supposed to pass static arrays to C functions? I'm asking
 because I'm getting conflicting info from how DMD works and on IRC.

 The below example prints:
 test1 0x7fff857c1db0
 test2 0x7fff857c1db0
 test3 (nil)
 test4 0x7fff857c1db0


 D:
 void main()
 {
         float[3] arr;
         test1(arr);
         test2(&arr[0]);
         test3(0, arr);
         test4(0, &arr[0]);
 }

 extern(C):
 void test1(float[3] arr);
 void test2(float *arr);
 void test3(int, float[3] arr);
 void test4(int, float *arr);


 C:
 #include <stdio.h>

 void test1(float arr[3]) { printf("test1 %p\n", &arr[0]); }
 void test2(float arr[3]) { printf("test2 %p\n", &arr[0]); }
 void test3(int anything, float arr[3]) { printf("test3 %p\n", &arr[0]); }
 void test4(int anything, float arr[3]) { printf("test4 %p\n", &arr[0]); }

That seems weird. Since static arrays are passed by value in D you need to send a reference:

Yeah I'm wondering if this isn't a bug.

In D, static arrays are passed by value, in C by pointer. Hence, you have a mismatch between the C and D prototypes of test1, and you'll get garbage results.
Oct 24 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Walter Bright:

 In D, static arrays are passed by value, in C by pointer. 
 Hence, you have a mismatch between the C and D prototypes of 
 test1, and you'll get garbage results.

Isn't it possible to help the programmer avoid some similar mistakes with some warnings or errors? I think the extern(C) annotation, plus the function signatures, give the D compiler all the info it needs. Bye, bearophile
Oct 24 2012
next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 10/24/12, bearophile <bearophileHUGS lycos.com> wrote:
 Isn't it possible to help the programmer avoid some similar
 mistakes with some warnings or errors?

 I think the extern(C) annotation, plus the function signatures,
 give the D compiler all the info it needs.

Agreed. File to bugzilla unless Walter disagrees?
Oct 24 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 10/24/12, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 Agreed. File to bugzilla unless Walter disagrees?

Also, what should the error message look like? I've got a pull in works fwiw.
Oct 24 2012
prev sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 10/24/12, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 On 10/24/12, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 Agreed. File to bugzilla unless Walter disagrees?

Also, what should the error message look like? I've got a pull in works fwiw.

Small test-case: extern(C) void fail(int[4] x); extern(C) int[4] fail2(); extern(C) void c_ok1(ref int[4] x); extern(C) void c_ok2(out int[4] x); extern(C) void c_ok3(int[4]* x); extern(C) ref int[4] c_ok4(); extern(C) int[4]* c_ok5(); Have I covered everything?
Oct 24 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Andrej Mitrovic:

The issue you have opened is:
http://d.puremagic.com/issues/show_bug.cgi?id=8887


 Have I covered everything?

The implementation of D associative arrays is opaque, so why is this allowed? extern(C) void foo(int[int] aa); void main() {} Bye, bearophile
Oct 24 2012
parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 10/24/12, bearophile <bearophileHUGS lycos.com> wrote:
 Andrej Mitrovic:

 The issue you have opened is:
 http://d.puremagic.com/issues/show_bug.cgi?id=8887

And pull https://github.com/D-Programming-Language/dmd/pull/1215
 The implementation of D associative arrays is opaque, so why is
 this allowed?

 extern(C) void foo(int[int] aa);
 void main() {}

Well this is less dangerous than the OP case, but maybe it should be disallowed. Another bug should be opened for this.
Oct 24 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/24/2012 12:54 AM, Jakob Bornecrantz wrote:
 How are you supposed to pass static arrays to C functions?

C accepts static arrays as pointers, so T[n] in D would be C prototyped as T*. Pass a pointer to the first element.
Oct 24 2012
parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Wednesday, 24 October 2012 at 09:16:30 UTC, Walter Bright 
wrote:
 C accepts static arrays as pointers, so T[n] in D would be C 
 prototyped as T*.

 Pass a pointer to the first element.

In GCC (or any c compiler) isn't it possible in optimizing to copy the static array to the stack (say 8 bytes or less as a guess)? Course this assumes the static size is set as part of the function signature too... It makes sense for it to work both ways (in their own way); But then more bugs can lie in wait as well.
Oct 24 2012
parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
On 24-10-2012 12:00, Era Scarecrow wrote:
 On Wednesday, 24 October 2012 at 09:16:30 UTC, Walter Bright wrote:
 C accepts static arrays as pointers, so T[n] in D would be C
 prototyped as T*.

 Pass a pointer to the first element.

In GCC (or any c compiler) isn't it possible in optimizing to copy the static array to the stack (say 8 bytes or less as a guess)? Course this assumes the static size is set as part of the function signature too... It makes sense for it to work both ways (in their own way); But then more bugs can lie in wait as well.

Passing static arrays by reference to the first element is part of the calling convention/ABI. If the C compiler generated code that doesn't work this way, the C compiler has a bug. -- Alex Rønne Petersen alex lycus.org http://lycus.org
Oct 24 2012