7
votes

I am working on a project which uses C - Ada language binding. A function in C will call a function in Ada side. I want to make a variadic function in Ada which can receive a variable number of arguments sent from the C function. I also wanted to send different types of args at the same time like int, char, enums, etc at the same time. Is it possible to have this type of mechanism?

4
I don't know if it's possible, Ada is extremely strongly typed and vararg functions break that. - Some programmer dude
No. You need a distinct Ada subprogram for each call profile you want to make. See the GNAT User Guide. .... wait, if you’re not using GNAT it might just be possible; ask your compiler vendor. - Simon Wright

4 Answers

5
votes

The forthcoming Ada standard Ada 202x is planning to provide support for calling C variadic functions.

You would then be able to write;

package C renames Interfaces.C;

procedure Printf (Format : in C.char_array)
  with Import => True, Convention => C_Variadic_1, External_Name => "printf";
3
votes

You cannot create a variadic function in Ada. You can simulate a variadic function is a couple of ways.

  1. Ada allows you to specify default values for functions and procedures. One need not always specify the values of the default parameters if you want to use the default values.
  2. You can define one or more of the parameters as a variant record.
2
votes

It is not possible to call any C variadic function from Ada in a portable way!

One of the reason - some ABIs use special ways/registers to pass float values. This mean C compiler will use this registers, due to it's unknown in advance whether argument is float or not. Ada compiler will not use this registers (since you can't put float parameter in Ada wrapper function declaration). As result you will get crash, stack corruption or any other undefined behavior.

Particularly AMD64 ABI specifies:

%rax - with variable arguments passes information about the number of vector registers used

%xmm0–%xmm1 - used to pass and return floating point arguments

The only portable solution is using C wrapper with fixed number of parameters, then bind it as usual.

0
votes

You can use 'address or the package System.Address_To_Access_Conversions and 'access (or 'unchecked_access) to generate addresses of each item you want to pass.

   type Address_Array is array (positive range <>) of System.address;
   function C_Caller(Params : Address_Array) return Integer is begin return 0; end;
   X, Y, Z, Result : Integer;
begin
   result := C_Caller(Address_Array'(x'address, y'address, z'address));

...then you'll need to pragma import the actual function.