Приведение ClutterActor* к ClutterStage*

Я изучаю возможность создания привязки Clutter для языка D ( http://d-programming-language.org/) и начали с нескольких простых тестов с динамической загрузкой libclutter. Я столкнулся с проблемой, которая может быть связана с системой наследования GObject, и я был бы признателен за любую помощь в ее решении. Вот краткое изложение: использование clutter_stage_get_default возвращает ClutterActor*, который я могу использовать с методами clutter_actor_*. Но я всегда получаю ошибки или segfaults, когда использую методы clutter_stage_* или clutter_container_*. Вот мой тестовый код: http://pastebin.com/nVrQ69dU

При вызове clutter_container_add_actor в строке 56 я получаю следующую ошибку: (<unknown>:11976): Clutter-CRITICAL **: clutter_container_add_actor: assertion 'CLUTTER_IS_CONTAINER (container)' failed

В примере кода я заметил макросы CLUTTER_STAGE и CLUTTER_CONTAINER для приведения (очевидно, они мне недоступны), но, насколько я мог судить, они просто выполняли какие-то проверки, а затем выполняли простое приведение C. Если это неверно, и перед кастингом над указателем сцены необходимо выполнить какую-то магию типа Gobject, сообщите мне об этом. Связывание и использование clutter_stage_set_title или clutter_stage_set_color с cast(ClutterStage*)stage приводило к ошибкам сегментации, предположительно той же проблеме.

РЕДАКТИРОВАТЬ: Вот урезанный пример без внешних зависимостей (если вы не используете Linux, вам нужно будет заменить вызовы dl эквивалентами вашей ОС). Этот код завершается ошибкой сегментации, которая, согласно GDB и Valgrind, находится в clutter_stage_set_title (in /usr/lib/libclutter-glx-1.0.so.0.600.14).


person Justin W    schedule 06.06.2011    source источник


Ответы (2)


Проблема в том, что вы не объявляете функции C как extern(C). Из-за этого dmd думает, что вы вызываете функцию D, и использует неправильное соглашение о вызовах. Один из способов сделать это правильно выглядит следующим образом:

alias extern(C) void function(void*, const char*) setTitleFunc;
auto clutter_stage_set_title = getSym!(setTitleFunc)("clutter_stage_set_title");

Я не уверен, как заставить его работать без псевдонима. DMD отказывается анализировать что-либо с extern(C) в параметре шаблона:

auto clutter_stage_set_title = getSym!(extern(C) void function(void*, const char*))("clutter_stage_set_title"); //Doesn't work

Кстати: ваша функция cstring опасна: она возвращает символ *, указывающий, что строку можно изменить, но это не всегда так: если вы передаете строковый литерал в toStringz, он может не выделять новую память, а возвращать указатель исходной строки. вместо. Строковые литералы находятся в постоянной памяти, поэтому это может привести к проблемам.

Вы можете просто настроить свои типы функций, чтобы они соответствовали типам C (const gchar* в C --> const char* в D) и напрямую использовать toStringz.

person jpf    schedule 07.06.2011
comment
Ах, я не понимал, что мне нужно указать соглашение о вызовах C при динамической привязке, хотя в ретроспективе это имеет смысл. - person Justin W; 07.06.2011

структуры в D не могут наследоваться друг от друга, и приведение указателей на структуры вернет null, если нет промежуточного приведения к void* (в отличие от приведения C) Здесь меня опровергли

вам лучше добавить еще один уровень абстракции, используя структуры с дескриптором и эмулируя проверки из этих макросов при литье

но что произойдет, если вы сделаете

clutter_container_add_actor(cast(ClutterContainer*)(cast(void*)stage), textbox);

(сначала приведение к void*, а затем к ClutterContainer*)

person ratchet freak    schedule 06.06.2011
comment
Использование вашего предложения приводит к тем же результатам. Кроме того, приведение указателей структуры не приводит к нулевому значению — добавление writeln(stage); writeln(cast(ClutterContainer*)stage); дает два идентичных адреса памяти. Я использую DMD 2.053, если это имеет значение. - person Justin W; 07.06.2011
comment
@justin, возможно, вам просто придется использовать пустые указатели для дескрипторов Clutter, это то, что я видел в других библиотеках, взаимодействующих со структурами в стиле C. - person ratchet freak; 07.06.2011
comment
@justin или попробуйте получить точную структуру структур и воссоздать их в файлах интерфейса D и попробовать с этими - person ratchet freak; 07.06.2011
comment
Поскольку я просто передаю указатели от одной вспомогательной функции к другой, мне не нужно ничего знать о содержимом структур. Кроме того, отредактированный вопрос со ссылкой на упрощенный, не более чем пример void*. - person Justin W; 07.06.2011
comment
@justin, кстати, функции, которые вы импортируете, сделаны с использованием соглашения о вызовах C? - person ratchet freak; 07.06.2011
comment
Справочник по API можно посмотреть здесь: docs.clutter-project. org/docs/clutter/stable/ я перевожу их в соглашение D (например, void function(int*, char***) при привязке, поскольку стиль C больше не поддерживается DMD). - person Justin W; 07.06.2011
comment
@justin что произойдет, если вы вызовете clutter_stage_set_title(clutter_stage_get_default(), cstring("A window title"));, то есть обойдете ввод данных - person ratchet freak; 07.06.2011
comment
То же самое, ошибка seg в clutter_stage_set_title. Вот почему я подозреваю внутреннюю систему/беспорядок GObject. - person Justin W; 07.06.2011