www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Communication between D and C with dynamic arrays

reply "seany" <seany uni-bonn.de> writes:
In D, arrays are dynamic. However, to the best of my knowledge, 
in C, they are static.

I am having difficulty in imagining how to send D arrays to a C 
function.

My first Idea was to make a pointer to the array. then find the 
size of the array, which itself is an array, therefore take the 
pointer to it, then get the dimension of the array, which is an 
integer, and send the trio of two pointers and the dimesion to 
the C code.

Now this arises two questions :

1. I assume that D allocates a particular space to the array, say 
N elements, and up to these N elements, you can increment the 
pointers, to jump to next array element.

What happens if the N element space is used up? Does the pointer 
incrementing method break down?

2. in D pointers are being converted to void * as I read in the 
reply to another post of mine. I dont remember in my knowledge of 
C, that they are accepted in C, are they? Do I have to meake a 
type retrospection every time I get send something to C?

Any help is appreciated.

PS: is there a built in size operator for arrays in D?
Aug 10 2014
next sibling parent reply ketmar via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Sun, 10 Aug 2014 14:26:27 +0000
seany via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:

 I am having difficulty in imagining how to send D arrays to a C=20
 function.
do something like this: =3D=3D=3D C SIDE =3D=3D=3D void c_array_processing (int *items, size_t item_count) { // use items pointer as normal C-like array pointer ... } =3D=3D=3D D SIDE =3D=3D=3D extern(C) void c_array_processing (int* items, size_t item_count); int[] arr; ... arr ~=3D 42; ... c_array_processing(arr.ptr, arr.length);
 PS: is there a built in size operator for arrays in D?
if you want to get size of all array items, do this: size_t dataSize =3D arr[0].sizeof*arr[0].length; if you want to get the size of the internal array structure... just don't do that. it's better to not use internal compiler and runtime structures.
Aug 10 2014
parent reply "seany" <seany uni-bonn.de> writes:
Thank you, so the running out of space problem is taken care of 
automatically?
Aug 10 2014
parent reply ketmar via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Sun, 10 Aug 2014 15:24:29 +0000
seany via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:

 Thank you, so the running out of space problem is taken care of=20
 automatically?
from D side -- yes. just don't store passed pointer on C side, 'cause it can be changed on array resize. but if you want to be able to resize the array from C side, than this is completely different story. D has it's own memory maganer, so you can't easily use malloc() and company from libc.
Aug 10 2014
parent reply "seany" <seany uni-bonn.de> writes:
On Sunday, 10 August 2014 at 15:34:30 UTC, ketmar via 
Digitalmars-d-learn wrote:

 from D side -- yes. just don't store passed pointer on C side, 
 'cause
 it can be changed on array resize.
Excellent, So if I have int [] array; void * ptr_to_array = &array; /* populate array here */ C_Function(ptr_to_array); /* repopulate array here, the pointer itself may change, but the variable ptr_to_array will be updated accordingly */ C_Function(ptr_to_array); I am okey? Also, similar arguments with structs apply?
Aug 10 2014
parent reply "anonymous" <anonymous example.com> writes:
On Sunday, 10 August 2014 at 15:37:41 UTC, seany wrote:
 On Sunday, 10 August 2014 at 15:34:30 UTC, ketmar via 
 Digitalmars-d-learn wrote:

 from D side -- yes. just don't store passed pointer on C side, 
 'cause
 it can be changed on array resize.
Excellent, So if I have int [] array; void * ptr_to_array = &array;
Don't do that. `&array` is not the same as `array.ptr`. Use `array.ptr`. `&array` would be a pointer to the local variable `array`.
 /* populate array here */

 C_Function(ptr_to_array);

 /* repopulate array here, the pointer itself may change, but 
 the variable ptr_to_array will be updated accordingly */


 C_Function(ptr_to_array);

 I am okey?
I'm not sure if you got that right: ptr_to_array will not be updated automatically. You have to do that yourself. Also, if C_Function has only one parameter which is a pointer, make sure the array has the proper length, or that is has a proper terminator element (char* arguments must usually be zero-terminated).
Aug 10 2014
parent reply "seany" <seany uni-bonn.de> writes:
So here is the final situtaion

I have a file: software_pluginInterface.di

Here I declare :

extern (C): void performComputation(char lib[], char func[], 
void* ptr[], int varNum );
// lib and func will be used later

Then i have the corresponding C file: software_pluginInterface.c, 
where I declare :

#include "stdio.h"
#include "string.h"

void performComputation(char lib[], char func[], void * v[], int 
varNum)
{

   printf("there are %d variables \n", varNum);

}



then I call this with :

performComputation(A, B, V, to!int(v.count()/3));

A, B are '\0' terminated char arrarys
V is a void pointer array with 6 elements


So I would expect a output like :
there are 2 variables

But I am getting : there are 1557197040 variables

Please help.
Aug 10 2014
parent reply "seany" <seany uni-bonn.de> writes:
of course I read this : http://dlang.org/interfaceToC.html

I have 64 bit OS
Aug 10 2014
parent reply "seany" <seany uni-bonn.de> writes:
Solved : 
http://stackoverflow.com/questions/25232194/c-and-d-communication/25232265#25232265
Aug 10 2014
parent ketmar via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Sun, 10 Aug 2014 19:39:29 +0000
seany via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:

 Solved :=20
 http://stackoverflow.com/questions/25232194/c-and-d-communication/2523226=
5#25232265 almost exactly what i wrote in my first reply. except that i wrote about using .ptr and size_t for item counter too.
Aug 10 2014
prev sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Sunday, 10 August 2014 at 14:26:29 UTC, seany wrote:
 In D, arrays are dynamic. However, to the best of my knowledge, 
 in C, they are static.

 I am having difficulty in imagining how to send D arrays to a C 
 function.

 My first Idea was to make a pointer to the array. then find the 
 size of the array, which itself is an array, therefore take the 
 pointer to it, then get the dimension of the array, which is an 
 integer, and send the trio of two pointers and the dimesion to 
 the C code.
In D, there both dynamic and static arrays. The static ones are those whose length is known at compile time, i.e. int[10] my_numbers; These are treated as value types, not references. When a function takes a static array, it receives a copy of the entire array, not a reference to it: void foo(int[4] data); This has no direct equivalent in C. Then there are dynamic arrays. Under the hood, a dynamic array with elements of type T is actually a struct (well, it behaves as if it is one): struct DynamicArray { size_t length; T* ptr; } With T being the specific type. (The length and ptr members might be in the opposite order.) You can always access the length and pointer of both types of arrays: void main() { import std.stdio; int[2] static_array; int[] dynamic_array; writeln(static_array.length); // 2 writeln(dynamic_array.length); // 0 dynamic_array ~= [1,2,3,4]; // append elements writeln(dynamic_array.length); // 4 // you can even set the length writeln(dynamic_array); // [1, 2, 3, 4] dynamic_array.length = 2; writeln(dynamic_array); // [1, 2] // growing fills the array with default value dynamic_array.length = 4; writeln(dynamic_array); // [1, 2, 0, 0] // slicing dynamic_array = static_array[]; // dyn.a. now points to stat.a. // dynamic_array.length == static_array.length // dynamic_array.ptr == static_array.ptr } The details of arrays in D are described here: http://dlang.org/arrays As for communicating with C, it depends. Some C functions only take a pointer to an array. They either already know the length from somewhere else, or they use a special value in the array as a signal that the array ends there. The latter is typically used for strings, which are defined to end with a 0 byte. For passing arrays to these C functions, you can use the `ptr` property; alternatively, you can take the address of the first element. extern(C) my_c_func(int* data); int[] a = [1,2,3,4,5]; my_c_func(a.ptr); my_c_func(&(a[0])); Of course, you may need to make sure that the array actually contains the magic value at its end. For strings, this can be done with std.string.toStringz: http://dlang.org/phobos/std_string.html#.toStringz In most cases, however, the C function also accepts the length of the array. For these, you need to use the `length` property: extern(C) my_other_c_func(int* data, size_t length); int[] b = [6,7,8,9]; my_other_c_func(b.ptr, b.length);
 Now this arises two questions :

 1. I assume that D allocates a particular space to the array, 
 say N elements, and up to these N elements, you can increment 
 the pointers, to jump to next array element.

 What happens if the N element space is used up? Does the 
 pointer incrementing method break down?
Yes, the array elements are stored next to each other in memory, without gaps. By default, D checks whether you are still inside the bounds of the array, and raises an error if you access an element outside of the bounds. But this only works if you access the array directly using an index, or slicing: int[] a = [10,11,12,13]; writeln(a[0]); // 10 writeln(a[3]); // 13 //writeln(a[4]); // ERROR // slicing: indices 1 (incl.) up to 3 (excl.) writeln(a[1 .. 3]); // [11, 12] // length is represented by $ writeln(a[2 .. $]); // [12, 13] //writeln(a[0 .. 5]); // ERROR You mentioned incrementing a pointer. This does work, just like in C, but if you do this, you are responsible for checking the array bounds. The language cannot help you there. If you access something outside of the array, it's undefined behaviour: int[] a = [20,30,40,50]; int* b = a.ptr; writeln(*b); // 20 writeln(b[0]); // 20 writeln(b[0 .. 4]); // [20, 30, 40, 50] //writeln(b[0 .. $]); // doesn't compiler, length is unknown b++; writeln(b[0]); // 30 //writeln(b[100]); // ??? // might print garbage, might crash, might eat your harddisk...
 2. in D pointers are being converted to void * as I read in the 
 reply to another post of mine. I dont remember in my knowledge 
 of C, that they are accepted in C, are they? Do I have to meake 
 a type retrospection every time I get send something to C?

 Any help is appreciated.
I think this is a misunderstanding. If you take a pointer to a variable of type `T` (or to an element of an array of `T`s), the pointer's type is `T*`. This is just like in C. `void*` is a special pointer type that you can use if you don't already know the real type it is pointing to, or if it is supposed to be opaque. This also exists in C. Which pointer type you need to use when calling a C function depends of course on that function: Just use whatever the function accepts.
 PS: is there a built in size operator for arrays in D?
For the `length` property (the number of elements), see above. There is also the `sizeof` property, which returns the actual size that a variable occupies in memory. But be careful: for dynamic arrays, `sizeof` returns either 8 or 16, depending on whether you are compiling 32bit or 64bit programs. This is because, as explained above, dynamic array variables are internally just a pair of length and pointer. int[] a; int[16] b; writeln(a.sizeof); // 16 writeln(b.sizeof); // 64
Aug 10 2014