1

I am working on a C-ADA binding project where I need to pass a String declared in ADA side to C functions. In one of the ADA function, I declared a bounded char array as:

Str_C : Interfaces.C.Char_Array(1..23) := (others => Interfaces.C.nul);

And declared a vector of type Char_Array_Access as:

Ptr1 : Interfaces.C.Strings.Char_Array_Access := Str_C'Access;

But the compiler fails to compile at the above mentioned vector initialization and says "prefix of "Access" attribute must be aliased"

(I didn't aliased the char_array previously because char_array type is already and aliased array of char).

OK, let's add aliased keyword to the char array declaration as:

Str_C : aliased Interfaces.C.Char_Array(1..23) := (others => Interfaces.C.nul);

but it still fails with an error on the vector line as: enter image description here

and a warning on the char array declaration line as: enter image description here

Don't know what is going wrong here. Any help would be appreciated!

LPs
  • 16,045
  • 8
  • 30
  • 61
Akay
  • 1,092
  • 12
  • 32
  • 1
    No, it is C-ADA binding, – Akay Mar 21 '16 at 10:29
  • Actually, it is the components of `char_array` objects that are **aliased** (character), but not the entire array objects of type `char_array` themselves. In the case of `char_array`, I imagine that the type matches C's way of referring to single characters of C arrays by pointer. As in `*(s+1)` for `s[1]`, for example, which shows how C "array" `s` is a pointer, to `char`, zeroth char, first char, second char, … of a string `s`. – B98 Mar 21 '16 at 19:11

2 Answers2

1

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));
B98
  • 1,229
  • 12
  • 20
  • I tried your code @B98 , but I am getting a compiler error "non-local pointer cannot point to local object" at Ptr1 declaration? – Akay Mar 21 '16 at 11:44
  • This says that your object was declared perhaps within in some subprogram, but is to be referenced via a pointer type that was declared at a more outer level (than the subprogram), like `chars_ptr` is (in the Ada library, couldn't get much more "outer"). This is a different, and quite general matter; I suggest you provide more context so that the issues can be treated separately. In particular: locally declared objects go away when the procedure is done, so if you take `'access`, you'd create a dangling pointer. Ada prevents that at compile time. – B98 Mar 21 '16 at 12:14
0

The function New-String is the perfect tool for what you want to do :

with Interfaces.C.Strings; use Interfaces.C.Strings;

procedure Main_Ada is

Nom : constant chars_Ptr := New_string("Charles Dupont");
...
Emile
  • 163
  • 6