Справочник по Ada 2012
B.3.2 Обобщенный пакет интерфейсов.C.Pointers
Обобщенный пакет 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
with Convention => Intrinsic;
function "+" (Left : in ptrdiff_t; Right : in Pointer) return Pointer
with Convention => Intrinsic;
function "-" (Left : in Pointer; Right : in ptrdiff_t) return Pointer
with Convention => Intrinsic;
function "-" (Left : in Pointer; Right : in Pointer) return ptrdiff_t
with Convention => Intrinsic;
with Convention => Intrinsic;
function "+" (Left : in ptrdiff_t; Right : in Pointer) return Pointer
with Convention => Intrinsic;
function "-" (Left : in Pointer; Right : in ptrdiff_t) return Pointer
with Convention => Intrinsic;
function "-" (Left : in Pointer; Right : in Pointer) return ptrdiff_t
with Convention => Intrinsic;
procedure Increment (Ref : in out Pointer)
with Convention => Intrinsic;
procedure Decrement (Ref : in out Pointer)
with Convention => Intrinsic;
with Convention => Intrinsic;
procedure Decrement (Ref : in out Pointer)
with Convention => Intrinsic;
Этот абзац был удален.
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. Если Ref равен null, генерируется исключение Interfaces.C.Strings.Dereference_Error.
function Value(Ref : in Pointer;
Length : in ptrdiff_t)
return Element_Array;
Length : in ptrdiff_t)
return Element_Array;
Эта функция возвращает Element_Array, содержащий первые Length элементов, на которые указывает Ref. Если Ref равен null, генерируется исключение Interfaces.C.Strings.Dereference_Error.
Функции «+» и «–» выполняют арифметические операции над значениями Pointer на основе размера элементов массива. В каждой из этих функций, если параметр Pointer равен null, генерируется Pointer_Error.
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 элементов, в зависимости от того, что произойдет раньше. Если Source или Target равны null, генерируется Dereference_Error.
procedure Copy_Array (Source : in Pointer;
Target : in Pointer;
Length : in ptrdiff_t);
Target : in Pointer;
Length : in ptrdiff_t);
Эта процедура копирует первые Length элементов из массива, на который указывает Source, в массив, на который указывает Target. Если Source или Target равны null, генерируется Dereference_Error.
Ошибки выполнения
Ошибка выполнения возникает при разыменовании указателя Pointer, не указывающего на алиасированный Element.
Выполнение Value(Ref, Terminator) приводит к ошибке выполнения, если Ref не указывает на алиасированный элемент Element в Element_Array, завершенном Terminator.
Выполнение Value(Ref, Length) приводит к ошибке выполнения, если Ref не указывает на алиасированный элемент Element в Element_Array, содержащем не менее Length элементов между указанным элементом и концом массива включительно.
Выполнение Virtual_Length(Ref, Terminator) приводит к ошибке выполнения, если Ref не указывает на алиасированный элемент Element в Element_Array, завершенном Terminator.
Выполнение Copy_Terminated_Array(Source, Target, Limit, Terminator) приводит к ошибке выполнения в следующих случаях:
- Выполнение как Value(Source, Terminator), так и Value(Source, Limit) приводит к ошибке, или
- Копирование записывает данные за пределами массива, содержащего элемент, на который указывает Target.
Выполнение Copy_Array(Source, Target, Length) приводит к ошибке выполнения, если либо Value(Source, Length) приводит к ошибке, либо копирование записывает данные за пределами массива, содержащего элемент, на который указывает Target.
ПРИМЕЧАНИЯ
10 Чтобы создать 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;