Я пытаюсь сделать interop с C++ и D. И то, что я нашел сегодня, действительно пугает мой разум: объекты не передаются правильно в моей программе.Как передать объект из D в C++?
Лучше показать пример.
У меня есть библиотека C++, которую я компилирую в объектный файл и программу D, которую я связываю с моей библиотекой и запускаю.
Вот они:
#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);
}
И программа 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);
}
компилировать их с этими командами:
c++ -c my_core.cpp -o my_core.o
dmd main.d my_core.o -L-lstdc++
Но когда я бегу ./main
, я получил странное результаты:
(113244372, 1, 42)
Что заставило меня думать, что объекты передаются неправильно, просто эксперимент. Во-первых, я побежал мою программу несколько раз, и вот что я увидел:
$ ./main
(266442332, 1, 42)
$ ./main
(234899036, 1, 42)
$ ./main
(109475420, 1, 42)
Таким образом, первый номер, кажется, указатель на блок памяти. И мое шестое чувство в паре с знаниями о сборке заставляет меня думать, что это указатель на переменную this
.
И теперь, только, чтобы подтвердить мои данные все еще на месте, и эти цифры не просто случайные те, я добавил еще два поля для моего класса Color
:
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);
}
И программа 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);
}
И выходы:
$ ./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)
Я пробовал скомпилировать мою программу как с компиляторами DMD, так и с LDC, но оба предоставили мне точно такое же поведение.
UPD: Что еще более интересно и (вероятно) указывая, где проблема заключается, является тот факт, объекты, созданные в Lib C++ в настоящее время проходит между D и C++ правильно.
Чтобы доказать это, я создал "фабричный метод" в моем Color
классе:
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);
}
А потом, в D программе:
Color c = Color.create(42, 7, 19, 499, 727);
printer.print(c);
Так что c
объект приходит из библиотеки C++, передается в объект printer
, созданный в библиотеке C++, и эта передача выполняется в программе D.
И результаты неожиданно правильно:
$ ./main
(42, 7, 19, 499, 727)
Я пропускаю понятия C++ и D Interop или это ошибка в двух D составителей (недоверчиво)?
AFAIK это дизайн. D способен взаимодействовать с C++, но он не может самостоятельно создавать объекты C++ (а объекты D имеют разный бинарный макет). Использование фабричного метода кажется правильным. –