Справочное описание GObject |
---|
C API определяет набор функций и глобальные переменные которые обычно экспортируются из бинарных. C функции имеют произвольное количество аргументов и одно возвращаемое значение. Каждая функция идентифицируется уникальным именем функции и набором C типов которые описывают аргументы функции и возвращаемое значение. Глобальные переменные экспортируемого API также идентифицируются их именем и типом.
Таким образом C API определяется набором имён с которыми связаны наборы типов. Если вам известны правила вызова функции и отображение C типов в машинные типы используемые на вашей платформе, вы можете транслировать имя каждой функции чтобы найти код связанный с этой функцией в распределённой памяти, а зтем создать правильный список аргументов для функции. Наконец, всё что вы должны сделать это переключить вызов целевой C функции со списком аргументов.
Для дальнейшего обсуждения, рассмотрим простую C функцию и связанный 32 bit x86 ассемблерный код сгенерированный gcc на моей linux машине:
static void function_foo (int foo)
{}
int main (int argc, char *argv[])
{
function_foo (10);
return 0;
}
push $0xa
call 0x80482f4 <function_foo>
Ассемблерный код показанный выше достаточно прямолинейный: первая инструкция помещает
шестнадцатеричное значение 0xa (числовое значение 10) как 32 bit целочисленное в стек и вызывает
function_foo
. Как вы видите, вызов C функции осуществлён gcc непосредственным вызовом функции
(вероятно это самая быстрая из возможных реализаций).
Теперь, скажем нам нужно вызвать C функцию function_foo
из
программы написанной на языке python. Чтобы это сделать, интерпретатору python необходимо:
Найти расположение функции. Это вероятно означает поиск в бинарном коде сгенерированном C компилятором который экспортирован этой функцией.
Загрузка функции в исполняемую память.
Конвертация python параметров в C-совместимые параметры перед вызовом функции.
Вызов функции с соблюдением соглашения о вызовах
Конвертация возвращаемого значения C функции в python-совместимую переменную для возвращения её в python код.
Процессс описанный выше довольно сложен и есть много способов сделать его полностью автоматическим и прозрачным для C и Python программистов:
Первое решение заключается в ручном написании совмещающего кода, для каждой экспортируемой или импортируемой функции, который выполняет конвертацию параметров python в C и конвертацию возвращаемого значения C в python. Этот совмещающий код связывается с интерпретатором который позволяет программам вызывать python функции делегирующие работу в C функцию.
Другой, намного лучше, автоматически генерировать совмещающий код, для каждой экспортируемой или импортируемой функции, со специальным компилятором который читает оригинальную сигнатуру функции.
Решение используемое GLib заключается в применении GType библиотеки которая содержит во время выполнения описание всех объектов которыми манипулирует программист. Эта, так называемая библиотека динамического типа [1], используется специальным основным кодом совмещения для автоматической конвертации параметров функции и согласует вызов функции между разными областями исполнения.
Самое большое преимущество реализуемое GType в том, что код совмещения находящийся в границе области исполнения пишется один раз: схема ниже демонстрирует это более ясно.
В настоящее время, существует по крайней мере основной код совмещения для Python и Perl, который позволяет использовать
C объекты написанные с помощью GType непосредственно в Python или Perl, с минимальными доработками: нет необходимости генерировать
огромное количество кода совмещения вручную или автоматически.
Хотя цель была достаточно похвальной, главной задачей является в целом библиотека GType/GObject. C программисты вероятно будут озадачены сложностью особенностей демонстрируемых в следующих главах, если они забудут, что библиотека GType/GObject была разработана не только для объектно-ориентированных улучшений C прграммистам, но и для прозрачной крос-языковой функциональной совместимости.
[1] Есть многочисленные различные реализации систем динамических типов: все C++ компиляторы имеют такую систему, Java и .NET имеют её тоже. Система динамического типа позволяет вам получать информацию о каждом созданном динамическом объекте. Это может быть реализовано с помощью определённой для процесса базы данных: каждый новый объект создаёт регистры характеристик связанного с ним типа в системе. так же это может быть реализовано интерфейсом самоанализа. Общим пунктом между всеми этими разными системами типа и реализациями является то, что они позволяют вам делать запрос метаданных динамического объекта.