It is about the explict subtype constraints 1..23
on the left side, the subtype bounds on Str_C
's type char_array
, I think. The (private) pointer type chars_ptr
is to unconstrained objects without bounds, reflecting C's char*
(which knows no bounds). So, declare the object like this:
Str_C : aliased Interfaces.C.char_array := (1..23 => Interfaces.C.nul);
Ptr1 : Interfaces.
C.Strings.chars_ptr := Interfaces.C.Strings.To_Chars_Ptr(Str_C'access);
To_Chars_Ptr
does the necessary pointer conversion. The declarations actually reflect the compiler's diagnosis.
It might be worth considering To_Ada
, To_C
, and Convention
identifiers, together with a language feature: Ada passes arrays to C functions as C pointers. This is documented in LRM Annex B.3 (see Implementation Advice). So, you could store Ada strings, if you liked, on the Ada side.
Since the problem seems to also involve accessibility of pointed-to objects (e.g., of an array declared within a subprogram), here are some ways around that. See LRM 3.10.2 for details. The important question to ask is: "Do the objects exist when pointers to them could still be passed around?" Making sure that objects exist after a subprogram is done, say, can be achieved by allocating the arrays in the subprogram, as opposed to declaring them as variables on the stack. (Stack variables will essentially be gone after the call). Or, if you really know what you are doing, you can force the compiler to ignore that a pointer may outlive its object by using 'Unchecked_Access
and not 'Access
.
Ptr2 : Interfaces.C.Strings.chars_ptr := -- DANGER AHEAD!
Interfaces.C.Strings.To_Chars_Ptr(Str_C'UNCHECKED_ACCESS);
Ptr3 : Interfaces.C.Strings.Chars_Ptr := Interfaces.C.Strings.To_Chars_Ptr
(new Interfaces.C.char_array'(1..23 => Interfaces.C.nul));
Ptr4 : Interfaces.C.Strings.Chars_Ptr :=
Interfaces.C.Strings.New_Char_Array((1..23 => Interfaces.C.nul));