www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - static arrays in C functions

reply Lutger <lutger.blijdestijn gmail.com> writes:
Since a while some extern(C) functions which take arrays seem to be broken. 
Can anybody clarify /confirm how they should be declared? 

For example I stumbled upon this:

import core.sys.posix.unistd, std.stdio;

void main()
{
    int[2] fd;
    writeln( pipe(fd) ); // failes with errno == EFAULT
}

In core.sys.posix.unistd, pipe is declared as: int pipe(int[2]);


This works though:

extern (C) { int pipe(int*); }

void main()
{
    int[2] fd;
    writeln( pipe(fd.ptr) ); 
}
Dec 08 2009
parent reply Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 8, 2009 at 2:08 AM, Lutger <lutger.blijdestijn gmail.com> wrote=
:
 Since a while some extern(C) functions which take arrays seem to be broke=
n.
 Can anybody clarify /confirm how they should be declared?

 For example I stumbled upon this:

 import core.sys.posix.unistd, std.stdio;

 void main()
 {
 =A0 =A0int[2] fd;
 =A0 =A0writeln( pipe(fd) ); // failes with errno =3D=3D EFAULT
 }

 In core.sys.posix.unistd, pipe is declared as: int pipe(int[2]);


 This works though:

 extern (C) { int pipe(int*); }

 void main()
 {
 =A0 =A0int[2] fd;
 =A0 =A0writeln( pipe(fd.ptr) );
 }
(Assuming you're talking about D2 here...) A few releases ago fixed-size arrays changed to be pass-by-value. But I guess there's still some logic in there to interpret int[2] as int* when inside an extern(C) block. It does seem like there's a bug there, though. I think pipe(fd) in the first case should fail to compile because it's attempting to pass by value where a pointer is expected. --bb
Dec 08 2009
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 08 Dec 2009 11:53:12 -0500, Bill Baxter <wbaxter gmail.com> wrote:

 On Tue, Dec 8, 2009 at 2:08 AM, Lutger <lutger.blijdestijn gmail.com>  
 wrote:
 Since a while some extern(C) functions which take arrays seem to be  
 broken.
 Can anybody clarify /confirm how they should be declared?

 For example I stumbled upon this:

 import core.sys.posix.unistd, std.stdio;

 void main()
 {
    int[2] fd;
    writeln( pipe(fd) ); // failes with errno == EFAULT
 }

 In core.sys.posix.unistd, pipe is declared as: int pipe(int[2]);


 This works though:

 extern (C) { int pipe(int*); }

 void main()
 {
    int[2] fd;
    writeln( pipe(fd.ptr) );
 }
(Assuming you're talking about D2 here...) A few releases ago fixed-size arrays changed to be pass-by-value. But I guess there's still some logic in there to interpret int[2] as int* when inside an extern(C) block.
No it compiles *because* that logic is not there. It now thinks int[2] is a pass-by-value entity. It links because you are using C linkage which does not do name-mangling. I could define pipe as: extern (C) int pipe(char c, int x, float y); and it will still link :)
 It does seem like there's a bug there, though.  I think pipe(fd) in
 the first case should fail to compile because it's attempting to pass
 by value where a pointer is expected.
The error is either: a) you now need to declare C functions that were declared in C taking an array to taking a pointer, so core.sys.posix.unistd (and likely others) needs to be fixed. b) as you suggested, inside a C block, int[2] should be interpreted as int *. I'd prefer a, because I don't care much about direct translation of C headers :) If b is chosen as a solution, I'd also like to have the compiler automatically pass the pointer when calling a C function. -Steve
Dec 08 2009
parent Lutger <lutger.blijdestijn gmail.com> writes:
Steven Schveighoffer wrote:

 On Tue, 08 Dec 2009 11:53:12 -0500, Bill Baxter <wbaxter gmail.com> wrote:
 
 On Tue, Dec 8, 2009 at 2:08 AM, Lutger <lutger.blijdestijn gmail.com>
 wrote:
 Since a while some extern(C) functions which take arrays seem to be
 broken.
 Can anybody clarify /confirm how they should be declared?

 For example I stumbled upon this:

 import core.sys.posix.unistd, std.stdio;

 void main()
 {
    int[2] fd;
    writeln( pipe(fd) ); // failes with errno == EFAULT
 }

 In core.sys.posix.unistd, pipe is declared as: int pipe(int[2]);


 This works though:

 extern (C) { int pipe(int*); }

 void main()
 {
    int[2] fd;
    writeln( pipe(fd.ptr) );
 }
(Assuming you're talking about D2 here...) A few releases ago fixed-size arrays changed to be pass-by-value. But I guess there's still some logic in there to interpret int[2] as int* when inside an extern(C) block.
No it compiles *because* that logic is not there. It now thinks int[2] is a pass-by-value entity. It links because you are using C linkage which does not do name-mangling. I could define pipe as: extern (C) int pipe(char c, int x, float y); and it will still link :)
Interesting, I didn't realize that but it makes sense!
 
 It does seem like there's a bug there, though.  I think pipe(fd) in
 the first case should fail to compile because it's attempting to pass
 by value where a pointer is expected.
The error is either: a) you now need to declare C functions that were declared in C taking an array to taking a pointer, so core.sys.posix.unistd (and likely others) needs to be fixed. b) as you suggested, inside a C block, int[2] should be interpreted as int *. I'd prefer a, because I don't care much about direct translation of C headers :) If b is chosen as a solution, I'd also like to have the compiler automatically pass the pointer when calling a C function. -Steve
Thanks for the explanation, looks like there is some work to do in the binding department. This looks like a case where a piece of C code silently does something different in D.
Dec 08 2009