Справочное руководство по Ada 95
B.3.2 Общие пакеты интерфейсов.C.Указатели
Общий пакет Interfaces.C.Pointers позволяет программисту Ada выполнять операции в стиле C с указателями. Он включает тип доступа Pointer, функции Value, которые разыменовывают указатель Pointer и возвращают обозначенный массив, несколько операций арифметики указателей и процедуры «копирования», которые копируют содержимое исходного указателя в массив, обозначаемый целевым указателем. Как и в C, он рассматривает объект Ptr типа Pointer как указатель на первый элемент массива, так что, например, добавление 1 к Ptr даёт указатель на второй элемент массива.
Общий пакет поддерживает два стиля использования: один, в котором массив завершается специальным терминальным элементом; и другой, в котором программист должен отслеживать длину.
Статическая семантика
В общем пакете библиотеки Interfaces.C.Pointers есть следующее объявление:
generic
type Index is (<>);
type Element is private;
type Element_Array is array (Index range <>) of aliased Element;
Default_Terminator : Element;
package Interfaces.C.Pointers is
pragma Preelaborate(Pointers);
type Index is (<>);
type Element is private;
type Element_Array is array (Index range <>) of aliased Element;
Default_Terminator : Element;
package Interfaces.C.Pointers is
pragma Preelaborate(Pointers);
type Pointer is access all Element;
function Value(Ref : in Pointer;
Terminator : in Element := Default_Terminator)
return Element_Array;
Terminator : in Element := Default_Terminator)
return Element_Array;
function Value(Ref : in Pointer;
Length : in ptrdiff_t)
return Element_Array;
Length : in ptrdiff_t)
return Element_Array;
Pointer_Error : exception;
-- Арифметика указателей в стиле C
function "+" (Left : in Pointer; Right : in ptrdiff_t) return Pointer;
function "+" (Left : in ptrdiff_t; Right : in Pointer) return Pointer;
function "-" (Left : in Pointer; Right : in ptrdiff_t) return Pointer;
function "-" (Left : in Pointer; Right : in Pointer) return ptrdiff_t;
function "+" (Left : in ptrdiff_t; Right : in Pointer) return Pointer;
function "-" (Left : in Pointer; Right : in ptrdiff_t) return Pointer;
function "-" (Left : in Pointer; Right : in Pointer) return ptrdiff_t;
procedure Increment (Ref : in out Pointer);
procedure Decrement (Ref : in out Pointer);
procedure Decrement (Ref : in out Pointer);
pragma Convention (Intrinsic, "+");
pragma Convention (Intrinsic, "-");
pragma Convention (Intrinsic, Increment);
pragma Convention (Intrinsic, Decrement);
pragma Convention (Intrinsic, "-");
pragma Convention (Intrinsic, Increment);
pragma Convention (Intrinsic, Decrement);
function Virtual_Length (Ref : in Pointer;
Terminator : in Element := Default_Terminator)
return ptrdiff_t;
Terminator : in Element := Default_Terminator)
return ptrdiff_t;
procedure Copy_Terminated_Array
(Source : in Pointer;
Target : in Pointer;
Limit : in ptrdiff_t := ptrdiff_t'Last;
Terminator : in Element := Default_Terminator);
(Source : in Pointer;
Target : in Pointer;
Limit : in ptrdiff_t := ptrdiff_t'Last;
Terminator : in Element := Default_Terminator);
procedure Copy_Array (Source : in Pointer;
Target : in Pointer;
Length : in ptrdiff_t);
Target : in Pointer;
Length : in ptrdiff_t);
end Interfaces.C.Pointers;
Тип Pointer совместим с C и соответствует одному использованию «Element *» в C. Объект типа Pointer интерпретируется как указатель на начальный Element в Element_Array. Поддерживаются два стиля:
- Явное завершение значения массива Default_Terminator (специальное значение терминатора);
- Управление длиной программистом, при этом Default_Terminator рассматривается просто как элемент данных.
function Value(Ref : in Pointer;
Terminator : in Element := Default_Terminator)
return Element_Array;
Terminator : in Element := Default_Terminator)
return Element_Array;
Эта функция возвращает Element_Array, значение которого представляет собой массив, на который указывает Ref, до и включая первый Terminator; нижняя граница массива — Index'First. Interfaces.C.Strings.Dereference_Error распространяется, если Ref — null.
function Value(Ref : in Pointer;
Length : in ptrdiff_t)
return Element_Array;
Length : in ptrdiff_t)
return Element_Array;
Эта функция возвращает Element_Array, содержащий первые Length элементов, на которые указывает Ref. Исключение Interfaces.C.Strings.Dereference_Error распространяется, если Ref — null.
Функции «+» и «-» выполняют арифметические операции над значениями Pointer, основываясь на размере элементов массива. В каждой из этих функций Pointer_Error распространяется, если параметр Pointer — null.
procedure Increment (Ref : in out Pointer);
Эквивалентно Ref := Ref+1.
procedure Decrement (Ref : in out Pointer);
Эквивалентно Ref := Ref-1.
function Virtual_Length (Ref : in Pointer;
Terminator : in Element := Default_Terminator)
return ptrdiff_t;
Terminator : in Element := Default_Terminator)
return ptrdiff_t;
Возвращает количество элементов, до первого Terminator, в Value(Ref, Terminator).
procedure Copy_Terminated_Array
(Source : in Pointer;
Target : in Pointer;
Limit : in ptrdiff_t := ptrdiff_t'Last;
Terminator : in Element := Default_Terminator);
(Source : in Pointer;
Target : in Pointer;
Limit : in ptrdiff_t := ptrdiff_t'Last;
Terminator : in Element := Default_Terminator);
Эта процедура копирует Value(Source, Terminator) в массив, на который указывает Target; она останавливается, либо после копирования Terminator, либо после копирования Limit элементов, в зависимости от того, что произойдёт раньше. Dereference_Error распространяется, если Source или Target — null.
procedure Copy_Array (Source : in Pointer;
Target : in Pointer;
Length : in ptrdiff_t);
Target : in Pointer;
Length : in ptrdiff_t);
Эта процедура копирует первые Length элементов из массива, на который указывает Source, в массив, на который указывает Target. Dereference_Error распространяется, если Source или Target — null.
Ошибки выполнения
Некорректно разыменовывать Pointer, не обозначающий aliased Element.
Выполнение Value(Ref, Terminator) некорректно, если Ref не обозначает aliased Element в Element_Array, завершённом Terminator.
Выполнение Value(Ref, Length) некорректно, если Ref не обозначает aliased Element в Element_Array, содержащем как минимум Length элементов между обозначенным Element и концом массива включительно.
Выполнение Virtual_Length(Ref, Terminator) некорректно, если Ref не обозначает aliased Element в Element_Array, завершённом Terminator.
Выполнение Copy_Terminated_Array(Source, Target, Limit, Terminator) некорректно в следующих ситуациях:
- Выполнение Value(Source,Terminator) и Value(Source,Limit) некорректно, или
- Копирование записывает за пределы массива, содержащего Element, обозначаемый Target.
Выполнение Copy_Array(Source, Target, Length) некорректно, если Value(Source, Length) некорректно или копирование записывает за пределы массива, содержащего Element, обозначаемый Target.
ПРИМЕЧАНИЯ
14 Для создания Pointer из Element_Array используйте 'Access на первом элементе. Например (предполагая соответствующие инстанцирования):
Some_Array : Element_Array(0..5) ;
Some_Pointer : Pointer := Some_Array(0)'Access;
Some_Pointer : Pointer := Some_Array(0)'Access;
Примеры
Пример Interfaces.C.Pointers:
with Interfaces.C.Pointers;
with Interfaces.C.Strings;
procedure Test_Pointers is
package C renames Interfaces.C;
package Char_Ptrs is
new C.Pointers (Index => C.size_t,
Element => C.char,
Element_Array => C.char_array,
Default_Terminator => C.nul);
with Interfaces.C.Strings;
procedure Test_Pointers is
package C renames Interfaces.C;
package Char_Ptrs is
new C.Pointers (Index => C.size_t,
Element => C.char,
Element_Array => C.char_array,
Default_Terminator => C.nul);
use type Char_Ptrs.Pointer;
subtype Char_Star is Char_Ptrs.Pointer;
subtype Char_Star is Char_Ptrs.Pointer;
procedure Strcpy (Target_Ptr, Source_Ptr : Char_Star) is
Target_Temp_Ptr : Char_Star := Target_Ptr;
Source_Temp_Ptr : Char_Star := Source_Ptr;
Element : C.char;
begin
if Target_Temp_Ptr = null or Source_Temp_Ptr = null then
raise C.Strings.Dereference_Error;
end if;
Target_Temp_Ptr : Char_Star := Target_Ptr;
Source_Temp_Ptr : Char_Star := Source_Ptr;
Element : C.char;
begin
if Target_Temp_Ptr = null or Source_Temp_Ptr = null then
raise C.Strings.Dereference_Error;
end if;
loop
Element := Source_Temp_Ptr.all;
Target_Temp_Ptr.all := Element;
exit when C."="(Element, C.nul);
Char_Ptrs.Increment(Target_Temp_Ptr);
Char_Ptrs.Increment(Source_Temp_Ptr);
end loop;
end Strcpy;
begin
...
end Test_Pointers;
Element := Source_Temp_Ptr.all;
Target_Temp_Ptr.all := Element;
exit when C."="(Element, C.nul);
Char_Ptrs.Increment(Target_Temp_Ptr);
Char_Ptrs.Increment(Source_Temp_Ptr);
end loop;
end Strcpy;
begin
...
end Test_Pointers;