Next: , Previous: B.3.1, Up: B.3


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

        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;

11

        procedure Increment (Ref in out Pointer);
        procedure Decrement (Ref in out Pointer);

12

        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

19

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
{erroneous execution (cause) [partial]} 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
{erroneous execution (cause) [partial]} Execution of Value(Ref, Terminator) is erroneous if Ref does not designate an aliased Element in an Element_Array terminated by Terminator.

37
{erroneous execution (cause) [partial]} 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
{erroneous execution (cause) [partial]} Execution of Virtual_Length(Ref, Terminator) is erroneous if Ref does not designate an aliased Element in an Element_Array terminated by Terminator.

39
{erroneous execution (cause) [partial]} Execution of Copy_Terminated_Array(Source, Target, Limit, Terminator) is erroneous in either of the following situations:

40

41

42
{erroneous execution (cause) [partial]} 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.

     NOTES

43

12  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 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/00658652/0065} {00142AI95−00142−01}       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;