1

I have problems passing D struct that contains static array to C.

D code:

extern (C){
    struct vec3f{
        float[3] array;
    }

    void testVec3f(vec3f v);
}

...

void test(){
    float[3] ar = [1f,2f,3f];
    vec3f v = vec3f(ar);
    testVec3f(v);
}

C code:

extern "C" struct vec3f{
    float array[3];
};

extern "C" void testVec3f(vec3f a){
    printf("x=%f, y=%f, z=%f\n", a.array[0], a.array[1], a.array[2]);

}

Result: x=0.000000, y=0.000000, z=0.000000. I also checked that both structs in D and C have the same size - 12 bytes.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
Rulli
  • 35
  • 4
  • 1
    why are you putting extern "C" in your C code? – Ahmed Masud Apr 12 '18 at 19:45
  • @AhmedMasud because I use c++ compiler. Is it a problem ? – Rulli Apr 12 '18 at 19:50
  • Yes, it is! C++ is **not** C! They are very different languages, one ot the obvious differnces is exactly waht you use. Others are moresubtle. Learn the language before tagging it. – too honest for this site Apr 12 '18 at 19:56
  • Ok, but I also tried `extern (C++)` without `extern "C"` on C++ side. Also casting `vec3f` to a struct where float[3] is represented as 3 continuous float fields, like x,y,z, make it work. – Rulli Apr 12 '18 at 20:02
  • It makes a difference, because of the way linkages occur, extern "C" should produce a C compatible object, however not sure you are linking things correctly, can you post the command line you are using to bind the objects? – Ahmed Masud Apr 12 '18 at 20:05
  • Things are complicated :) I use cmake + cuda + clang. And here is the most important line (no extra link or compiler flags): `cuda_add_library(voxelizedBindings STATIC ... sampling.cu)` `vec3f` struct is in sampling.cu – Rulli Apr 12 '18 at 20:10

1 Answers1

2

You are going to run into a whole host of trouble trying to pass structs by value between C and D; especially if your D compiler uses gnu compiler on the back end whereas you may be using clang++ for some parts of your project.

The way gnu c++ and clang++ treat object passing is different, extern "C" adds another layer of complexity. You are best off avoiding all of that and pass your values by reference:

Here your example (working correctly) using clang-c++ and dmd:

test.d:

import std.stdio;

struct vec3f {
    float [3] array;
}

extern (C) {
    void print_vec3f(vec3f *v);
}
void main()
{
    vec3f v = vec3f([1f, 2f, 3f]);
    print_vec3f(&v);
}

vect3.cc:

#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif 

struct vec3f {
        float array[3];
};

void print_vec3f(struct vec3f *v)
{
    printf("x: %f, y: %f, z: %f\n", v->array[0], v->array[1], v->array[2]);
}

#ifdef __cplusplus
};
#endif

Compile using:

clang++ -o vect3.o -c vect3.cc
dmd   test.d vect3.o

./test
x: 1.000000, y: 2.000000, z: 3.000000
Ahmed Masud
  • 21,655
  • 3
  • 33
  • 58