I am trying to do interop with C ++ and D. And what I found today really confuses my mind: objects are not being transferred correctly in my program.
Better to show an example.
I have a C ++ library that I compile into an object file and a D program that I link to my library and run.
Here they are:
#include <stdio.h> class Color { public: Color(unsigned int _r, unsigned int _g, unsigned int _b) : r(_r), g(_g), b(_b) {} unsigned int r, g, b; }; class Printer { public: Printer() {} ~Printer() {} static Printer* getInstance(); void print(Color *c); }; Printer* Printer::getInstance() { return new Printer(); } void Printer::print(Color *c) { printf("(%d, %d, %d)\n", c->r, c->g, c->b); }
And program D:
import std.stdio; extern(C++) { class Color { uint r, g, b; this(uint _r, uint _g, uint _b) { r = _r; g = _g; b = _b; } } class Printer { @disable this(); static Printer getInstance(); final void print(Color c); } } void main() { auto printer = Printer.getInstance(); Color c = new Color(42, 7, 19); printer.print(c); }
I will compile them with the following commands:
c++ -c my_core.cpp -o my_core.o dmd main.d my_core.o -L-lstdc++
But when I started ./main
, I got strange results:
(113244372, 1, 42)
What made me think that objects are being transmitted incorrectly is just an experiment. Firstly, I ran my program a couple of times, and this is what I saw:
$ ./main (266442332, 1, 42) $ ./main (234899036, 1, 42) $ ./main (109475420, 1, 42)
So, the first number looks like a pointer to a block of memory. And my sixth sense paired with build knowledge makes me think it's a pointer to the this
variable.
And now, to confirm that my data still exists, and that these numbers are not random, I added two more fields to my Color
class:
C ++ lib:
#include <stdio.h> class Color { public: Color(unsigned int _r, unsigned int _g, unsigned int _b, unsigned int _u, unsigned int _v) : r(_r), g(_g), b(_b), u(_u), v(_v) {} unsigned int r, g, b, u, v; }; class Printer { public: Printer() {} ~Printer() {} static Printer* getInstance(); void print(Color *c); }; Printer* Printer::getInstance() { return new Printer(); } void Printer::print(Color *c) { printf("(%d, %d, %d, %d, %d)\n", c->r, c->g, c->b, c->u, c->v); }
And program D:
import std.stdio; extern(C++) { class Color { this(uint _r, uint _g, uint _b, uint _u, uint _v) { r = _r; g = _g; b = _b; u = _u; v = _v; } uint r, g, b, u, v; } class Printer { @disable this(); static Printer getInstance(); final void print(Color c); } } void main() { auto printer = Printer.getInstance(); Color c = new Color(42, 7, 19, 499, 727); printer.print(c); }
And outputs:
$ ./main (90379876, 1, 42, 7, 19) $ ./main (79758948, 1, 42, 7, 19) $ ./main (74901092, 1, 42, 7, 19) $ ./main (217458276, 1, 42, 7, 19) $ ./main (238933604, 1, 42, 7, 19)
I tried to compile my program with both DMD and LDC compilers, but both provided me with exactly the same behavior.
UPD: What is even more interesting and (possibly) indicates where the problem lies is the fact that objects created in C ++ lib are passed between D and C ++ correctly.
To prove this, I created a factory method in the Color
class:
static Color* create(unsigned int _r, unsigned int _g, unsigned int _b, unsigned int _u, unsigned int _v) { return new Color(_r, _g, _b, _u, _v); }
And then in program D:
Color c = Color.create(42, 7, 19, 499, 727); printer.print(c);
So, the object c
comes from the C ++ library, is passed to the printer
object created in the C ++ library, and this transfer is performed in the program D.
And the results are unexpectedly true:
$ ./main (42, 7, 19, 499, 727)
Am I missing the concepts of C ++ and D interop or is it a mistake in two D compilers (with doubt)?