Re: Translating C "static arrays" into D?

2018-02-26 Thread H. S. Teoh via Digitalmars-d
On Mon, Feb 26, 2018 at 06:25:42PM +, Atila Neves via Digitalmars-d wrote:
[...]
> There's a common misconception in C that arrays and pointers are the
> same thing - they're not. This comes about because of the dubious C
> feature whereby arrays decay into pointers in function calls. Somewhat
> related to this, a little known feature of C is pointers to arrays. In
> your example, that's what y and z are. They have funky syntax and look
> like function pointers, unless they're obscured with a typedef as in
> your example.
> 
> You can pass a double array of any size to x, or a pointer to double,
> but y and z are constrained to be pointers to arrays of size 1.
> Exemplified:
> 
> typedef double mytype[1];
> void func1(mytype x);
> void func2(mytype* x);
> 
> int main() {
> double arr1[1];
> double arr2[2];
> double* ptr;
> 
> func1(arr1); // fine
> func1(arr2); // fine
> func1(ptr);  // fine
> 
> func2(&arr1); // fine
> func2(&arr2); // oops - won't compile
> }

Ouch.  After working with C for more than 20 years, this one still
escaped me. :-(  How I hate C array semantics...


On Mon, Feb 26, 2018 at 01:33:58PM -0500, Steven Schveighoffer via 
Digitalmars-d wrote:
[...]
> If you declare mytype as:
> 
> alias mytype = double[1];
> 
> Then you can use it pretty much anywhere. The only exception is when
> it's the exact type of a parameter. In that case, use ref:
> 
> extern(C) void someFunc(ref mytype x, mytype *y, mytype **z);
[...]

Nice, that's also the solution I eventually converged on.


T

-- 
Let's eat some disquits while we format the biskettes.


Re: Translating C "static arrays" into D?

2018-02-26 Thread Steven Schveighoffer via Digitalmars-d

On 2/26/18 12:54 PM, H. S. Teoh wrote:

What's the correct translation of the following C declarations into D?

typedef double[1] mytype;

void someFunc(mytype x, mytype *y, mytype **z);

struct SomeStruct {
mytype x;
mytype *y;
mytype **z;
}

I need this to interface with an external C library.  Currently, I just
wrapped the above as-is inside an extern(C) block.  But I suspect it may
be wrong, because:

1) In C, declaring a function parameter of type double[1] is, IIRC, the
same thing as declaring it as double*.  But in D, double[1] passes one
double by value as a static array. So there may be an API mismatch here.


If you declare mytype as:

alias mytype = double[1];

Then you can use it pretty much anywhere. The only exception is when 
it's the exact type of a parameter. In that case, use ref:


extern(C) void someFunc(ref mytype x, mytype *y, mytype **z);

-Steve


Re: Translating C "static arrays" into D?

2018-02-26 Thread ketmar via Digitalmars-d

H. S. Teoh wrote:


On Mon, Feb 26, 2018 at 08:07:11PM +0200, ketmar via Digitalmars-d wrote:
[...]

in C, arrays are *always* decaying to pointers. so
void foo (int x[2])
is the same as
void foo (int* x)
`[2]` is purely informational.
that is, in D it will be:
alias mytype = double*;


Actually, that doesn't work, because in the struct declaration it will
be wrong:

// C
struct S {
double[5] x; // actually occupies the space of 5 doubles
}

// D
struct S {
double* x; // occupies the space of 1 pointer (wrong)
}


yeah, sorry. somehow i completely missed structs.


Re: Translating C "static arrays" into D?

2018-02-26 Thread Atila Neves via Digitalmars-d

On Monday, 26 February 2018 at 17:54:12 UTC, H. S. Teoh wrote:
What's the correct translation of the following C declarations 
into D?


typedef double[1] mytype;


This isn't valid C, but `typedef double mytype[1];` is.



void someFunc(mytype x, mytype *y, mytype **z);

struct SomeStruct {
mytype x;
mytype *y;
mytype **z;
}

I need this to interface with an external C library.  
Currently, I just wrapped the above as-is inside an extern(C) 
block.  But I suspect it may be wrong, because:


1) In C, declaring a function parameter of type double[1] is, 
IIRC, the same thing as declaring it as double*.  But in D, 
double[1] passes one double by value as a static array. So 
there may be an API mismatch here.


Yes, a `double[1]` parameter in C and `double*` are the same 
thing. However, that's not valid for the other two parameters (y 
and z).


There's a common misconception in C that arrays and pointers are 
the same thing - they're not. This comes about because of the 
dubious C feature whereby arrays decay into pointers in function 
calls. Somewhat related to this, a little known feature of C is 
pointers to arrays. In your example, that's what y and z are. 
They have funky syntax and look like function pointers, unless 
they're obscured with a typedef as in your example.


You can pass a double array of any size to x, or a pointer to 
double, but y and z are constrained to be pointers to arrays of 
size 1. Exemplified:


typedef double mytype[1];
void func1(mytype x);
void func2(mytype* x);

int main() {
double arr1[1];
double arr2[2];
double* ptr;

func1(arr1); // fine
func1(arr2); // fine
func1(ptr);  // fine

func2(&arr1); // fine
func2(&arr2); // oops - won't compile
}





2) In C, declaring a *variable* or struct field as double[1] 
has essentially the same semantics as D's static arrrays.  
Meaning that I cannot just change the declaration of mytype in 
order to get the correct behaviour of function parameters.


3) I'm getting a segfault at runtime of some C++ code into D, 
that calls
the library via this C API, and I suspect it's probably due to 
(1).


The correct translation is:

extern(C) void someFunc(double* x, double[1]* y, double[1]** z);


Atila


Re: Translating C "static arrays" into D?

2018-02-26 Thread H. S. Teoh via Digitalmars-d
On Mon, Feb 26, 2018 at 08:07:11PM +0200, ketmar via Digitalmars-d wrote:
[...]
> in C, arrays are *always* decaying to pointers. so
> 
>   void foo (int x[2])
> 
> is the same as
> 
>   void foo (int* x)
> 
> `[2]` is purely informational.
> 
> that is, in D it will be:
> 
>   alias mytype = double*;

Actually, that doesn't work, because in the struct declaration it will
be wrong:

// C
struct S {
double[5] x; // actually occupies the space of 5 doubles
}

// D
struct S {
double* x; // occupies the space of 1 pointer (wrong)
}

Furthermore, declaring it as `double*` breaks existing code ported from
C:

// Original C code:
void foo(mytype x);
mytype z;
foo(z);

// D code:
void foo(double* x);// OK
mytype z;   // NG
foo(z); // NG: passes uninitialized pointer

// alternatively:
double[1] z;
foo(z); // NG: need to insert `&` to compile

Eventually I figured out a (hackish) solution to make it work without
silently breaking transliterated C code: declare all function parameters
that take `mytype` as ref.  This causes the D compiler to simulate the
array -> pointer degradation semantics but still retain "static array"
semantics in structs and variable declarations, without requiring a
change in syntax.


T

-- 
Food and laptops don't mix.


Re: Translating C "static arrays" into D?

2018-02-26 Thread ketmar via Digitalmars-d

H. S. Teoh wrote:


What's the correct translation of the following C declarations into D?

typedef double[1] mytype;

void someFunc(mytype x, mytype *y, mytype **z);

struct SomeStruct {
mytype x;
mytype *y;
mytype **z;
}

I need this to interface with an external C library.  Currently, I just
wrapped the above as-is inside an extern(C) block.  But I suspect it may
be wrong, because:

1) In C, declaring a function parameter of type double[1] is, IIRC, the
same thing as declaring it as double*.  But in D, double[1] passes one
double by value as a static array. So there may be an API mismatch here.

2) In C, declaring a *variable* or struct field as double[1] has
essentially the same semantics as D's static arrrays.  Meaning that I
cannot just change the declaration of mytype in order to get the correct
behaviour of function parameters.

3) I'm getting a segfault at runtime of some C++ code into D, that calls
the library via this C API, and I suspect it's probably due to (1).


T


in C, arrays are *always* decaying to pointers. so

void foo (int x[2])

is the same as

void foo (int* x)

`[2]` is purely informational.

that is, in D it will be:

alias mytype = double*;


Re: Translating C "static arrays" into D?

2018-02-26 Thread H. S. Teoh via Digitalmars-d
On Mon, Feb 26, 2018 at 09:54:12AM -0800, H. S. Teoh via Digitalmars-d wrote:
> What's the correct translation of the following C declarations into D?
> 
>   typedef double[1] mytype;

Sorry, typo, should be:

typedef double mytype[1];


>   void someFunc(mytype x, mytype *y, mytype **z);
> 
>   struct SomeStruct {
>   mytype x;
>   mytype *y;
>   mytype **z;
>   }
[...]


T

-- 
Real men don't take backups. They put their source on a public
FTP-server and let the world mirror it. -- Linus Torvalds


Translating C "static arrays" into D?

2018-02-26 Thread H. S. Teoh via Digitalmars-d
What's the correct translation of the following C declarations into D?

typedef double[1] mytype;

void someFunc(mytype x, mytype *y, mytype **z);

struct SomeStruct {
mytype x;
mytype *y;
mytype **z;
}

I need this to interface with an external C library.  Currently, I just
wrapped the above as-is inside an extern(C) block.  But I suspect it may
be wrong, because:

1) In C, declaring a function parameter of type double[1] is, IIRC, the
same thing as declaring it as double*.  But in D, double[1] passes one
double by value as a static array. So there may be an API mismatch here.

2) In C, declaring a *variable* or struct field as double[1] has
essentially the same semantics as D's static arrrays.  Meaning that I
cannot just change the declaration of mytype in order to get the correct
behaviour of function parameters.

3) I'm getting a segfault at runtime of some C++ code into D, that calls
the library via this C API, and I suspect it's probably due to (1).


T

-- 
Amateurs built the Ark; professionals built the Titanic.