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 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
prev sibling next 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 =?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
prev sibling next sibling parent "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
prev sibling next sibling parent "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
prev sibling next sibling parent "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
prev sibling 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 next sibling parent 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
prev sibling next sibling parent "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
prev sibling 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