It’s a bit more nefarious than that. In C, the complex macro from complex.h refers to the _Complex keyword (that’s not confusing at all, right??
).
For variables declared with the _Complex keyword, the implementation can define the underlying representation how it likes. It doesn’t have to be a structure, but it can be. That said, however it is implemented, the standard requires that it has the same representation and alignment as a 2 element array of the corresponding real type (float, double, long double). The first element must be the real part, and the second the imaginary. Implementations can still do this via struct, but they have to ensure the struct used conforms to those low level requirements (it has to map to the 2 element array as mentioned above).
C standard section 6.2.5 pg 11-13
11
There are three complex types, designated as float _Complex, double
_Complex, and long double _Complex.33) The real floating and complex types
are collectively called the floating types.
12
For each floating type there is a corresponding real type, which is always a
real floating type. For real floating types, it is the same type. For complex
types, it is the type given by deleting the keyword _Complex from the type
name.
13
Each complex type has the same representation and alignment requirements as an
array type containing exactly two elements of the corresponding real type; the
first element is equal to the real part, and the second element to the imaginary
part, of the complex number.
EDIT: I would probably still implement it as a struct on the Ada side for ease of use and readability, but you would want to do a record representation clause to ensure the values are placed according to the C standard requirements for correct mapping. And you would want to make sure the Size and Alignment were set correctly. I don’t know if you use Conventoin => C or Convention => C_Pass_By_Copy for it, but that’s easy to swap out and test. My initial guess is it will be C_Pass_By_Copy.
EDIT #2: This seems to work in godbolt:
with Interfaces.C;
with Ada.Text_IO; use Ada.Text_IO;
procedure Example is
Double_Size : constant := Interfaces.C.double'Size;
Double_Alignment : constant := Interfaces.C.double'Alignment;
type Complex is record
Real, Imaginary : Interfaces.C.double;
end record
with Size => 2 * Double_Size,
Alignment => Double_Alignment, -- C arrays are aligned by element alignment
Convention => C_Pass_By_Copy;
for Complex use record
Real at 0 range 0 .. Double_Size - 1;
Imaginary at Double_Alignment range 0 .. Double_Size - 1;
end record;
function C_Sin(Angle : Complex) return Complex
with Import, Convention => C, External_Name => "csin";
Value : constant Complex := C_Sin(Complex'(0.785398, 0.0));
begin
Put_Line("Result = " & Value'Image);
end Example;
Compiler Switches: -gnat2022 -largs -lm
Results:
Result =
(REAL => 7.07106665647094E-01,
IMAGINARY => 0.00000000000000E+00)