Преобразование ClutterActor * в ClutterStage*

#d #gobject #clutter

#d #gobject #беспорядок

Вопрос:

Я изучаю возможность создания привязки Clutter для языка D (http://d-programming-language.org /) и начали с того, что попробовали несколько простых тестов с использованием динамической загрузки libclutter. Я столкнулся с проблемой, которая может быть связана с системой наследования GObject, и я был бы признателен за любую помощь в ее решении. Вот краткое изложение: использование clutter_stage_get_default возвращает ClutterActor *, который я могу использовать с методами clutter_actor_ *. Но я всегда получаю ошибки или сбои в сегментах, когда я использую методы 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. Если это неверно, и перед приведением к указателю stage необходимо выполнить какую-то магию типа Gobject, пожалуйста, дайте мне знать. Привязка и использование clutter_stage_set_title или clutter_stage_set_color с cast(ClutterStage*)stage привели к ошибкам сегментации, предположительно, с той же проблемой.

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

Ответ №1:

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

 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 напрямую.

Комментарии:

1. Ах, я не понимал, что мне нужно было указывать соглашение о вызовах C при динамическом связывании, хотя, оглядываясь назад, это имеет смысл.

Ответ №2:

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

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

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

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

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

Комментарии:

1. Использование вашего предложения приводит к тем же результатам. Кроме того, приведение указателей структуры к нулевому значению не приводит writeln(stage); writeln(cast(ClutterContainer*)stage); к двум идентичным адресам памяти. Я использую DMD 2.053, если это имеет какое-либо значение.

2. @justin возможно, вам просто придется использовать указатели void для дескрипторов Clutter, это то, что я видел в других библиотеках, взаимодействующих со структурами в стиле C

3. @justin или попытайтесь получить точную структуру структур и воссоздать их в файлах общего интерфейса и попробуйте это с этими

4. Поскольку я просто передаю указатели от одной функции clutter к следующей, мне не нужно ничего знать о содержимом структур. Кроме того, отредактированный вопрос со ссылкой на упрощенный, ничего, кроме примера void *.

5. @justin кстати, импортируемые вами функции выполнены в соответствии с соглашением о вызовах C?