Menu:

Design and Sell Merchandise Online for Free

Interfacing to C from Ada95

In this tutorial I will take you through the steps of interfacing to C variables and functions. When creating bindings to libraries written in C from Ada a programmer really needs to know how to use the information contained within Appendix B of the Ada Reference Manual (ARM).

Binding variables

Firstly, I will show how to import a simple integer variable from C. Given the global variable declaration:

C code
/* A variable to import.
 */
int MyGlobal = 10;

The following Ada95 code can be used to bring it into the Ada program:

Ada95 code
  -- We want to link to the C MyGlobal variable here.
  My_Global : Interfaces.C.int;
  pragma Import(
    Convention    => C,
    Entity        => My_Global,
    External_Name => "MyGlobal");

I have used the named parameter passing mechanism so it's easier to see what's happening. We state that the linkage convention is C and the name we will give the integer in the Ada source is My_Global, we then provide the C name MyGlobal and the pragma binds the C name to the Ada name. We can then use the Ada name like this:

Ada95 code
  My_Global := 25;

Binding functions

Now following from this, we can extend this knowledge to importing a simple function from C:

C code
/* A function to import.
 */
int MyAdd(int a, int b)
    {
    return a + b;
    }

Again, using the same import pragma we can bring this function into the Ada program and make use of it:

Ada95 code
  -- We now want to import a function.
  function My_Add(A, B : Interfaces.C.int)
    return Interfaces.C.int;
  pragma Import(
    Convention    => C,
    Entity        => My_Add,
    External_Name => "MyAdd");

See how the C and Ada names differ? The pragma binds the 2 together so that they can be used in a program:

Ada95 code
  My_Global := My_Add(My_Global, 7);

Binding C strings

Strings in C are annoying as they can be viewed in a number of different ways. This also means that binding to them can be tricky. One way is to bind to a pointer to an array. So, for example say we have a function which returns a message string:

C code
/* A message to return to Ada.
 */
const char *Message = "This is a test string";

const char *MyString(void)
    {
    return Message;
    }

We want to import the MyString function into the Ada program. Ada provides access to pointers to char from the Interfaces.C.Strings package:

Ada95 code
  -- We have a function that returns a message in a string.
  function My_String return Interfaces.C.Strings.chars_ptr;
  pragma Import(
    Convention    => C,
    Entity        => My_String,
    External_Name => "MyString");

  -- This converts the char * array into an Ada String type.  
  Message : String := Interfaces.C.Strings.Value(My_String);

In the preceding code, we import as usual, but we use the chars_ptr type rather than the char_array type as we are passing a pointer and not a string from the stack. We can then transform this into an Ada String type by using the Value function.

Source code

I have placed a full example into an archive which can be built with GNAT using the following commands:

Bash code
$ tar -xzvpf importing_c.tgz
$ cd importing_c
$ make

Other Ada95 compilers will differ.

Download importing_c.tgz

suruena
Comment
C pointers and arrays
Reply #4 on : Mon November 19, 2007, 10:48:48
> I can see the use of the char array, but
> in C they are generally used interchangeably
> due to them being equivalent

Well, that's one way of thinking about it, but IMHO this is one of those cases where there is a real advantage in realising the differences between a pointer and an array, specially if you are coding an optimal shared library.

http://c-faq.com/aryptr/aryptr2.html
http://people.redhat.com/drepper/dsohowto.pdf

Best regards
Luke
Comment
Re:
Reply #3 on : Sat September 22, 2007, 16:24:09
Yeah, I can see the use of the char array, but in C they are generally used interchangeably due to them being equivalent, i.e. you still get a pointer to an array.

My_String will always send back the same string (the same address), but yeah, the Value will most likely produce multiple different String objects. That, I haven't looked into.
suruena
Comment
Re: constant
Reply #2 on : Mon September 17, 2007, 23:45:49
I think I should explain myself better. My first comment about declaring the Ada 'Message' variable as constant was because, due to the semantics of the program, the spec should forbid the modification of the string because the message should be the always the same, but NOT because this can lead to an erroneous behavior: the Value subprogram creates a new String object, different from the original C char array (which will probably by placed in a read-only memory -- .rodata section), and thus there is no problem if the programmer tries to modify the Ada String.
suruena
Comment
constant
Reply #1 on : Sat September 15, 2007, 15:43:12
Hi,

congratulations for the post, IMHO this is a good summary about interfacing with C from Ada. But I've some comments:

- The C string is declared as const, so in my opinion the Ada string should also be declared as constant (how to correctly reflect that the string returned by the Ada function is also constant is not so straightforward...).

Message : constant String
:= Interfaces.C.Strings.Value(My_String);

- In addition, I think in this C example the Message variable need not be a pointer, it can simply be an array of chars:

const char Message[] = "This is a test string";

Now there is no risk of smashing this pointer, and thus losing the address of the string.

Best regards,

Write a comment

  • Required fields are marked with *.

If you have trouble reading the code, click on the code itself to generate a new random code.
Security Code: *