Thread overview
two-dimensional C array and its analog in D
Aug 08, 2012
Alexandr Druzhinin
Aug 08, 2012
Ali Çehreli
Aug 08, 2012
Alexandr Druzhinin
Aug 08, 2012
BLM768
Aug 08, 2012
bearophile
Aug 08, 2012
bearophile
Aug 08, 2012
Alexandr Druzhinin
Aug 08, 2012
Ali Çehreli
Aug 08, 2012
Alexandr Druzhinin
August 08, 2012
Hello,
there is the following C function:

void foo(const void** data);

in C I can do:

int data[N][M];

data[0][0] = ..;
data[0][1] = ..;
data[1][0] = ..;
data[1][1] = ..;

foo(data); // for C code it works and in D code it doesn't (compile, but do nothing)

I've "solved" the problem like this:

int real_data[N*M];

real_data[0] = ..;
real_data[1] = ..;
real_data[2] = ..;
real_data[3] = ..;

int* data[N];
foreach(i; 0..N)
	data[i] = &real_data[i*M];

T.i. I form an array of pointers by myself without compiler so it doesn't seem to be good enough for some overcode and it looks dirty a little bit. Is there more suitable variant?

P.S. in few words I'd like to construct some D data structure that is binary compatible with two-dimensional C array (and do it in simple way, of course).

August 08, 2012
On 08/07/2012 11:07 PM, Alexandr Druzhinin wrote:
> Hello,
> there is the following C function:
>
> void foo(const void** data);
>
> in C I can do:
>
> int data[N][M];
>
> data[0][0] = ..;
> data[0][1] = ..;
> data[1][0] = ..;
> data[1][1] = ..;
>
> foo(data); // for C code it works and in D code it doesn't (compile, but
> do nothing)

This seems to work:

import std.stdio;

void main()
{
    enum M = 3;
    enum N = 4;

    int[M][N] data;
    data[0][0] = 42;
    writeln(data);
}

The output:

[[42, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]

Ali

August 08, 2012
Alexandr Druzhinin:

> there is the following C function:
>
> void foo(const void** data);
>
> in C I can do:
>
> int data[N][M];
>
> data[0][0] = ..;
> data[0][1] = ..;
> data[1][0] = ..;
> data[1][1] = ..;
>
> foo(data); // for C code it works and in D code it doesn't (compile, but do nothing)

That C code doesn't look correct, because the given data contains
no pointers.

Why don't you show us a complete compilable runnable correct tiny
C program, that we have to translate to D?

Bye,
bearophile
August 08, 2012
> That C code doesn't look correct, because the given data contains no pointers.

But this C code compiles:


void foo(const void** data) {}
int data[2][3];
int main() {
  foo(data);
  return 0;
}

Bye,
bearophile
August 08, 2012
08.08.2012 16:29, bearophile пишет:
>> That C code doesn't look correct, because the given data contains no
>> pointers.
>
> But this C code compiles:
>
>
> void foo(const void** data) {}
> int data[2][3];
> int main() {
>    foo(data);
>    return 0;
> }
>
> Bye,
> bearophile

As I know in C an array is equal to pointer, so array of array == array of pointers == pointer to pointer == pointer to array. Correct me if I'm wrong.

I'm trying to use OpenGL function glMultiDrawElements. It has signature:
void glMultiDrawElements(
  enum mode,
  sizei *count,
  enum type,
  void **indices,
  sizei primcount
);
If I declare indices like
uint[][] indices;
then code compiles but doesn't work (but it works in C). If I do as I described in the first post - it works in D. And I'd like to understand the reason of it. I think the reason is difference tween C array and D array, but I'm not sure.

p.s. example of real code is too large to paste
August 08, 2012
08.08.2012 12:13, Ali Çehreli пишет:
>
> This seems to work:
>
> import std.stdio;
>
> void main()
> {
>      enum M = 3;
>      enum N = 4;
>
>      int[M][N] data;
>      data[0][0] = 42;
>      writeln(data);
> }
>
> The output:
>
> [[42, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
>
> Ali
>

I mean that I call C function from D code. And C function takes void** pointer as its argument. In C this means array of array, but if I pass D two-dimensional array it doesn't work (but compiles).
August 08, 2012
> I mean that I call C function from D code. And C function takes void** pointer as its argument. In C this means array of array, but if I pass D two-dimensional array it doesn't work (but compiles).

I'm pretty sure that the issue is D's internal implementation of 2-dimensional arrays. From what I remember, if the arrays are defined as fixed-size, D creates just a single block of array data rather than creating pointers to pointers. OpenGL is expecting an array of pointers to 1-dimensional arrays, but D is giving it the pointer to the actual indices.
August 08, 2012
On 08/08/2012 07:12 AM, Alexandr Druzhinin wrote:
> 08.08.2012 16:29, bearophile пишет:
>>> That C code doesn't look correct, because the given data contains no
>>> pointers.
>>
>> But this C code compiles:
>>
>>
>> void foo(const void** data) {}
>> int data[2][3];
>> int main() {
>> foo(data);
>> return 0;
>> }

gcc does not accept that code:

deneme.c:18920: error: passing argument 1 of ‘foo’ from incompatible pointer type
deneme.c:18914: note: expected ‘const void **’ but argument is of type ‘int (*)[3]’

> As I know in C an array is equal to pointer,

In C and C++, an Array is automatically converted to a pointer to its first element.

> so array of array == array
> of pointers == pointer to pointer == pointer to array. Correct me if I'm
> wrong.
>
> I'm trying to use OpenGL function glMultiDrawElements. It has signature:
> void glMultiDrawElements(
> enum mode,
> sizei *count,
> enum type,
> void **indices,
> sizei primcount
> );

I looked at its online documentation: count is also an array that tells the lengths of individual rows of indices, right? So in reality the data is a dynamic ragged array? (I've never used that function before.)

> If I declare indices like
> uint[][] indices;

That's a slice of uint slices. Completely different memory layout than static arrays.

In any case, I am pretty sure that what you need is the .ptr property of D arrays. You will have to make the 'indices' parameter dynamically by calling .ptr on the slices.

> then code compiles but doesn't work (but it works in C). If I do as I
> described in the first post - it works in D. And I'd like to understand
> the reason of it. I think the reason is difference tween C array and D
> array, but I'm not sure.
>
> p.s. example of real code is too large to paste

I've started writing the following but I don't know how you are calling the function. Can you get this to do what you expect in C:

// WARNING: THIS C CODE DOES NOT COMPILE.
#include <stdio.h>

typedef size_t sizei;

void glMultiDrawElements(
    /* enum mode,*/
    sizei *count,
    /* enum type,*/
    void **indices,
    sizei primcount)
{
    for (size_t i = 0; i != primcount; ++i) {
        for (size_t j = 0; j != count[i]; ++j) {
            printf(" %d", indices[i][j]);
        }
        printf("\n");
    }
}

int main()
{
    /* Normally, the count array would be generated dynamically. */
    int counts[4] = { 3, 3, 3, 3 };

    int data[4][3];
    data[0][0] = 42;
    data[2][2] = 43;

    glMultiDrawElements(counts, data, 4);
}

Ali

-- 
D Programming Language Tutorial: http://ddili.org/ders/d.en/index.html

August 08, 2012
08.08.2012 22:21, Ali Çehreli пишет:
>
> I looked at its online documentation: count is also an array that tells
> the lengths of individual rows of indices, right? So in reality the data
> is a dynamic ragged array? (I've never used that function before.)

Yes, it is.

>
>  > If I declare indices like
>  > uint[][] indices;
>
> That's a slice of uint slices. Completely different memory layout than
> static arrays.

Ok. I'll read about slices once again

> In any case, I am pretty sure that what you need is the .ptr property of
> D arrays. You will have to make the 'indices' parameter dynamically by
> calling .ptr on the slices.

.ptr works fine. if I do, for example so:

uint[] firstSubArray;
uint[] secondSubArray;

uint*[] indicies;
indicies[0] = firstSubArray.ptr;
indicies[1] = secondSubArray.ptr;

that is I manually form array of pointers. But I don't like it.

>
> I've started writing the following but I don't know how you are calling
> the function. Can you get this to do what you expect in C:
>
> // WARNING: THIS C CODE DOES NOT COMPILE.
> #include <stdio.h>
>
> typedef size_t sizei;
>
> void glMultiDrawElements(
>      /* enum mode,*/
>      sizei *count,
>      /* enum type,*/
>      void **indices,
>      sizei primcount)
> {
>      for (size_t i = 0; i != primcount; ++i) {
>          for (size_t j = 0; j != count[i]; ++j) {
>              printf(" %d", indices[i][j]);
>          }
>          printf("\n");
>      }
> }
>
> int main()
> {
>      /* Normally, the count array would be generated dynamically. */
>      int counts[4] = { 3, 3, 3, 3 };
>
>      int data[4][3];
>      data[0][0] = 42;
>      data[2][2] = 43;
>
>      glMultiDrawElements(counts, data, 4);
> }

yes, it looks like what I mean, but I'm sleepy now :)