Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access c constant from Ada

Tags:

c

ada

I have a header file with a type definition like this

#ifndef SETSIZE
   #define SETSIZE 32
#endif

typedef struct _set {
    unsigned  array[SETSIZE];
} set_t;

To use a corresponding C-function I need to have the set_t type available in Ada. The problem is that SETSIZE is a configurable parameter (with default value 32). If I understand it correctly I cannot access preprocessor defines from Ada. Would it be possible to add a constant to the c-file and use this in Ada like this:

#ifndef SETSIZE
   #define SETSIZE 32
#endif

const size_t test = SETSIZE;
// Alternative
enum { test2 = SETSIZE };

--Ada--
-- import test somehow
type set_array is array (0 .. test) of aliased Interfaces.C.unsigned;
type set_t is record
  array_field : aliased set_array;
end record;

Or any other way to have this type correctly available in Ada without too much change in the original C-code

like image 603
the_summer Avatar asked Dec 20 '22 00:12

the_summer


2 Answers

Why not simply:

SetSize: constant Interfaces.C.Size_T;
pragma Import(
    Convention    => C,
    Entity        => SetSize,
    External_Name => "set_size" 
);

And in your C file:

const size_t set_size = SETSIZE;

Tested with gnatmake 4.8.1:

// File: set_def.c
#include <stdlib.h>

#ifndef SETSIZE
   #define SETSIZE 32
#endif

const size_t set_size = SETSIZE ;

typedef struct _set {
    unsigned  array[SETSIZE];
} set_t;

Compiling set_def.c:

Z:\> gcc -c set_def.c
-- File: main.adb
with Interfaces.C, Ada.Text_IO, Ada.Integer_Text_IO ;

procedure Main is

    use type Interfaces.C.Size_T ; -- To have access to the - operator

    SetSize: constant Interfaces.C.Size_T;

    pragma Import (
        Convention    => C,
        Entity        => SetSize,
        External_Name => "set_size" 
    );

    -- Note that you should go to SetSize - 1
    type Set_Array is array(0 .. SetSize - 1) of aliased Interfaces.C.Unsigned;
    type Set_T is
      record
        Array_Field: aliased Set_Array;
      end record;

    MySet: Set_T := (Array_Field => (1, 2, 3, others => 0)); 

begin
   Ada.Integer_Text_IO.Put (Integer(SetSize), 0); Ada.Text_IO.New_Line;
   Ada.Integer_Text_IO.Put (MySet.Array_Field'Length, 0); Ada.Text_IO.New_Line;
   for I in MySet.Array_Field'range loop
       Ada.Integer_Text_IO.Put (Integer(MySet.Array_Field(I)), 0);
       Ada.Text_IO.Put(' ');
   end loop;
end Main;

Compiling main.adb and linking with set_def.o:

Z:\> gnatmake main.adb -largs set_def.o
Z:\> main.exe
32
32
1 2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
like image 50
Holt Avatar answered Jan 07 '23 17:01

Holt


In a similar case what I did was to add a function to import from Ada:

size_t getsize(void) {
   return SETSIZE;
}

And in the Ada side:

function Getsize return Interfaces.C.size_t;
pragma Import(C, Getsize); -- From memory, this pragma is probably somewhat wrong

If you don't want to repeatedly call this function, for the (negligible I guess) overhead, you can have just after the function definition:

Setsize : constant Interfaces.C.size_t := Getsize;
-- Or convert to any more convenient type at this point.

I guess you could do the same with a variable too.

like image 38
Álex Avatar answered Jan 07 '23 17:01

Álex