Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I import a C-function to Ada with pass-by-reference arguments?

Tags:

ada

I have a C function int func( int a, int* b) that I need to import and use in Ada 95. Where the C function would typically be called in C as c = func(a, &b);

I import C functions all the time into Ada, but have always avoided using functions with pass by reference arguments, but it's finally time to learn.

I would like to know how to declare this function in Ada, and would also like a quick example of using it with declared variables shown (because I'm still a little fuzzy on the Access types).

Thanks all!

like image 776
gjcamann Avatar asked Jun 25 '12 13:06

gjcamann


1 Answers

In C, int* b can mean a lot of things. Perhaps it's really just a pointer to one variable, but it may also be an array for which int a is the length. This code assumes that int* b is actually just a value that's passed by reference:

with Interfaces.C;

-- ...
package C renames Interfaces.C;

function Func (A : C.int; B : access C.int) return C.int;
pragma Import (Convention => C, Entity => Func,
               External_Name => "func");

-- ...

declare
   A : C.int := 42;
   B : aliased C.int := 23;
   C : C.int;
begin
   C := Func (A, B'Access);
   -- ...
end;

You can use 'Access on aliased variables. This is safe as long as you're sure that the pointer won't be stored on the C side and accessed after the end of life of variable B. (If the C declaration uses the const keyword, you can use access constant on the Ada side, but that's Ada 2005 only.)

You can also use a named type:

-- ...
type Int_Access is access C.int;
function Func (A : C.int; B : Int_Access) return C.int;
-- ...
C := Func (A, B'Unchecked_Access);
-- ...

Now we need to use 'Unchecked_Access because Ada normally does not allow a non-local access type (as Int_Access) to refer to a local variable. If you know what the C code will do with the pointer (like you should), you can use named types to specify that no references to local variables should be passed.

Nota bene 1: If you have a procedure (in C: a function that returns void), you can specify a variable to be passed by reference by using in out in your Ada procedure declaration instead of access. This way, you do not need to worry about access types at all. As before, you need to be sure that the pointer is not stored at the C side.

Nota bene 2: Record types and arrays are passed by reference anyway - unless you specify pragma Convention (C_Pass_By_Copy, Your_Type);. This is a common gotcha when wrapping C functions in Ada.

like image 155
flyx Avatar answered Oct 20 '22 15:10

flyx