B.3.2 The Generic Package Interfaces.C.Pointers
1
The generic package Interfaces.C.Pointers allows
the Ada programmer to perform C-style operations on pointers. It includes
an access type Pointer, Value functions that dereference a Pointer and
deliver the designated array, several pointer arithmetic operations,
and “copy” procedures that copy the contents of a source
pointer into the array designated by a destination pointer. As in C,
it treats an object Ptr of type Pointer as a pointer to the first element
of an array, so that for example, adding 1 to Ptr yields a pointer to
the second element of the array.
2
The generic allows two styles of usage: one in which
the array is terminated by a special terminator element; and another
in which the programmer needs to keep track of the length.
Static Semantics
3
The generic library
package Interfaces.C.Pointers has the following declaration:
4
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);
5
type Pointer
is access all Element;
6
function Value(Ref :
in Pointer;
Terminator :
in Element := Default_Terminator)
return Element_Array;
7
function Value(Ref :
in Pointer;
Length :
in ptrdiff_t)
return Element_Array;
8
Pointer_Error :
exception;
9
-- C-style Pointer arithmetic
10/3
{
AI05-0229-1}
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;
11/3
{
AI05-0229-1}
procedure Increment (Ref :
in out Pointer)
with Convention => Intrinsic;
procedure Decrement (Ref :
in out Pointer)
with Convention => Intrinsic;
12/3
This paragraph
was deleted.{
AI05-0229-1}
pragma Convention (Intrinsic, "+");
pragma Convention (Intrinsic, "-");
pragma Convention (Intrinsic, Increment);
pragma Convention (Intrinsic, Decrement);
13
function Virtual_Length (Ref :
in Pointer;
Terminator :
in Element := Default_Terminator)
return ptrdiff_t;
14
procedure Copy_Terminated_Array
(Source :
in Pointer;
Target :
in Pointer;
Limit :
in ptrdiff_t := ptrdiff_t'Last;
Terminator :
in Element := Default_Terminator);
15
procedure Copy_Array (Source :
in Pointer;
Target :
in Pointer;
Length :
in ptrdiff_t);
16
end Interfaces.C.Pointers;
17
The type Pointer is
C-compatible and corresponds to one use of C's “Element *”.
An object of type Pointer is interpreted as a pointer to the initial
Element in an Element_Array. Two styles are supported:
18
Explicit termination of an array value with Default_Terminator
(a special terminator value);
19
Programmer-managed
length, with Default_Terminator treated simply as a data element.
20
function Value(Ref : in Pointer;
Terminator : in Element := Default_Terminator)
return Element_Array;
21
This function returns
an Element_Array whose value is the array pointed to by Ref, up to and
including the first Terminator; the lower bound of the array is Index'First.
Interfaces.C.Strings.Dereference_Error is propagated if Ref is null.
22
function Value(Ref : in Pointer;
Length : in ptrdiff_t)
return Element_Array;
23
This function returns
an Element_Array comprising the first Length elements pointed to by Ref.
The exception Interfaces.C.Strings.Dereference_Error is propagated if
Ref is null.
24
The "+" and
"–" functions perform arithmetic on Pointer values, based
on the Size of the array elements. In each of these functions, Pointer_Error
is propagated if a Pointer parameter is null.
25
procedure Increment (Ref : in out Pointer);
26
Equivalent to Ref
:= Ref+1.
27
procedure Decrement (Ref : in out Pointer);
28
Equivalent to Ref
:= Ref–1.
29
function Virtual_Length (Ref : in Pointer;
Terminator : in Element := Default_Terminator)
return ptrdiff_t;
30
Returns the number
of Elements, up to the one just before the first Terminator, in Value(Ref,
Terminator).
31
procedure Copy_Terminated_Array
(Source : in Pointer;
Target : in Pointer;
Limit : in ptrdiff_t := ptrdiff_t'Last;
Terminator : in Element := Default_Terminator);
32
This procedure copies
Value(Source, Terminator) into the array pointed to by Target; it stops
either after Terminator has been copied, or the number of elements copied
is Limit, whichever occurs first. Dereference_Error is propagated if
either Source or Target is null.
32.a
Ramification: It is the programmer's
responsibility to ensure that elements are not copied beyond the logical
length of the target array.
32.b
Implementation Note: The implementation
has to take care to check the Limit first.
33
procedure Copy_Array (Source : in Pointer;
Target : in Pointer;
Length : in ptrdiff_t);
34
This procedure copies the first Length elements
from the array pointed to by Source, into the array pointed to by Target.
Dereference_Error is propagated if either Source or Target is null.
Erroneous Execution
35
It is erroneous to dereference
a Pointer that does not designate an aliased Element.
35.a
Discussion: Such a Pointer could arise
via "+", "–", Increment, or Decrement.
36
Execution of Value(Ref, Terminator)
is erroneous if Ref does not designate an aliased Element in an Element_Array
terminated by Terminator.
37
Execution of Value(Ref, Length)
is erroneous if Ref does not designate an aliased Element in an Element_Array
containing at least Length Elements between the designated Element and
the end of the array, inclusive.
38
Execution of Virtual_Length(Ref,
Terminator) is erroneous if Ref does not designate an aliased Element
in an Element_Array terminated by Terminator.
39
Execution
of Copy_Terminated_Array(Source, Target, Limit, Terminator) is erroneous
in either of the following situations:
40
Execution of both Value(Source, Terminator) and
Value(Source, Limit) are erroneous, or
41
Copying writes past the end of the array containing
the Element designated by Target.
42
Execution of Copy_Array(Source,
Target, Length) is erroneous if either Value(Source, Length) is erroneous,
or copying writes past the end of the array containing the Element designated
by Target.
43
14 To compose
a Pointer from an Element_Array, use 'Access on the first element. For
example (assuming appropriate instantiations):
44
Some_Array : Element_Array(0..5) ;
Some_Pointer : Pointer := Some_Array(0)'Access;
Examples
45
Example of Interfaces.C.Pointers:
46
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);
47
use type Char_Ptrs.Pointer;
subtype Char_Star is Char_Ptrs.Pointer;
48
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;
49/1
{
8652/0065}
{
AI95-00142-01}
loop
Element := Source_Temp_Ptr.
all;
Target_Temp_Ptr.
all := Element;
exit when C."="(Element, C.nul) Element = C.nul;
Char_Ptrs.Increment(Target_Temp_Ptr);
Char_Ptrs.Increment(Source_Temp_Ptr);
end loop;
end Strcpy;
begin
...
end Test_Pointers;
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe