"Адское" программирование Ada-95 -Компилятор GNAT

         

Примеры организации взаимодействия с C



Примеры организации взаимодействия с C

Простым примером импорта C-функции может служить пример использования функции read системы UNIX в процедуре, написанной на Аде:

procedure Read( File_descriptor : in Integer; Buffer : in out String; No_Bytes : in Integer; No_Read : out Integer) is function Read( File_descriptor : Integer; Buffer : System.Address; No_Bytes : Integer) return Integer; pragma Import(C, read, "read");begin No_Read := Read(File_descriptor, Buffer(Buffer'First)'Address, No_Bytes); end Read;

Проблема связи с C возникает в ситуации,



когда необходимо взаимодействовать с функциями которые имеют список параметров с переменным числом параметров неоднородного типа.Примером такой функции может служить C-функция printf.Необходимо отметить, что подобные функции, по своей природе, не надежны, и не существует удовлетворительного способа решения этой проблемы.

Однако, Ада позволяет взаимодействовать с функциями, имеющими переменное число параметров, но при этом тип параметров однороден.Для взаимодействие с такими функциями можно использовать типы неограниченных (unconstrained) массивов.

Предположим, что существует функция, написанная на C, описание которой имеет следующий вид:

void something(*int[]);

Мы можем использовать эту функцию в Аде следующим образом:

type Vector is array(Natural range <>) of Integer;procedure Something(Item : Vector) is function C_Something(Address : System.Address); pragma Import(C, C_Something, "something");begin if Item'Length = 0 then C_Something(System.Null_Address); else C_Something(Item(Item'First)'Address); end if; end Something;

Рассмотрим более сложный пример, который демонстрирует использование C-функции execv системы UNIX, описанную в C следующим образом:

int execv(const char *path, char *const argv[]);

В данном случае, дополнительную сложность вызывает необходимость трансляции Ада-строк в массивы символов C-стиля.Перед тем как описывать непосредственную реализацию, необходимо сделать некоторые описания:

---------------------------------------------------------- type String_Ptr is access all String; type String_Array is array(Natural range <>) of String_Ptr;function execv( Path : String; Arg_List : String_Array) return Interfaces.C.Int;--------------------------------------------------------- -- execv заменяет текущий процесс на новый. -- Список аргументов передается как параметры командной -- строки для вызываемой программы. -- -- Для вызова этой подпрограммы можно: -- -- Option2 : aliased String := "-b"; -- Option3 : aliased String := "-c"; -- Option4 : String := "Cxy"; -- Result : Interfaces.C.Int; -- ... -- Result := execv(Path => "some_program", -- -- построение массива указателей на строки... -- argv => String_Array'(new String'("some_program"), -- new String'("-a"), -- Option2'Unchecked_Access, -- Option3'Unchecked_Access, -- new String'('-' & Option4)); -- -- Допустимо использовать любую комбинацию -- динамически размещаемых строк и 'Unchecked_Access -- к aliased переменным. -- Однако, необходимо отметить, что нельзя выполнить -- "some_String"'Access, поскольку Ада требует имя, -- а не значение, для отрибута 'Access------------------------------------------------------------

Теперь, реализация может быть выполнена следующим образом:

function execv( Path : String; argv : String_Array ) return Interfaces.C.Int is Package C renames Interfaces.C; Package Strings renames Interfaces.C.Strings; C_Path : constant Strings.Chars_Ptr(.Path'Length + 1) := Strings.New_String(Path); type Char_Star_Array is array(.argv'Length + 1) of Strings.Char_Array_Ptr; C_Argv : Char_Star_Array; Index : Integer; Result : C.int; ------------------------------------------------------------ function C_Execv( Path : Strings.Char_Ptr; C_Arg_List : Strings.Char_Ptr) return C.int; pragma Import(C, C_Execv, "execv"); ------------------------------------------------------------begin -- установка массива указателей на строки Index := 0; for I in argv'Range loop Index := Index + 1; C_Argv(Index) := Strings.New_String(argv(I).all)); end loop; -- добавление C-значения null в конец массива адресов C_Argv(C_Argv'Last) := Strings.Null_Ptr; -- передача адресов первых элементов каждого параметра, -- как это ожидает C Result := C_Execv( C_Path(1)'Address, C_Argv(1)'Address)); -- освобождение памяти, поскольку часто это не выполняется for I in argv'Range loop Strings.Free(argv(I)); end loop; Strings.Free(C_Path); return Result; end execv;

Примечательно, что передается адрес первого элемента массива, а не адрес самого массива.Массивы, описываемые как неограниченные, зачастую содержат вектор с дополнительной информацией, которая включает верхнюю и нижнюю границу массива.

Содержание раздела








Forekc.ru
Рефераты, дипломы, курсовые, выпускные и квалификационные работы, диссертации, учебники, учебные пособия, лекции, методические пособия и рекомендации, программы и курсы обучения, публикации из профильных изданий