Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ada to C++: Pass an unsigned 64-bit value

Tags:

c++

interface

ada

I need to pass 2 pieces of data from an Ada program to some C++ code for processing.

  • Data - double.
  • Time - unsigned 64 bits.

I was able to make a procedure in Ada that worked with my C++ method using a Long_Float (double in C++) and Integer (int in C++, obviously not 64-bits though). I used the following code (code not on me so syntax might be slightly off):

procedure send_data (this : in hidden_ptr; data : in Long_Float; time : in Integer);
pragma import (CPP, send_data, "MyClass::sendData");

Now that that's working, I'm trying to expand the time to the full 64-bits and ideally would like to have an unsigned long long on the C++ side. I don't see any types in Ada that match that so I created my own type:

type U64 is mod 2 ** 64;

When using that type with my send_data method I get an error saying there are no possible ways to map that type to a C++ type (something along those lines, again don't have the code or exact error phrase on me).

Is there a way to pass a user-defined type in Ada to C++? Perhaps there's another type in Ada I can use as an unsigned 64-bit value that would work? Is there a way to pass the address of my U64 type as a parameter to the C++ method instead if that's easier? I'm using the green hills adamulti compiler v3.5 (very new to ada, not sure if that info helps or not). Examples would be greatly appreciated!

like image 640
Xeelot Avatar asked Sep 20 '12 00:09

Xeelot


People also ask

How to bind C code with Ada?

We can successfully bind our C code with Ada using the automatically-generated bindings, but they aren't ideal. Instead, we would prefer Ada bindings that match our (human) interpretation of the C header file. This requires manual analysis of the header file.

How to use variables in Ada with C?

In the C application, we just need to declare the variable and use it: Again, by running the application, we see that the value from the counter is the number of times that my_func was called. In the examples above, we manually added aspects to our Ada code to correspond to the C source-code we're interfacing with.

How to handle 64 bit integers in C language?

The long long data type makes handling 64 bit integers easy. In C language, an unsigned number over 32 bits cannot exceed the value of 4,294,967,295. You may find you are required to handle larger numbers and for this you need these numbers to be coded in 64-bit. However, this is not handled in the same way as an ordinary integer.

How do I interface with C in Ada?

Ada allows us to interface with code in many languages, including C and C++. This section discusses how to interface with C. By default, when using gprbuild we only compile Ada source files. To compile C files as well, we need to modify the project file used by gprbuild. We use the Languages entry, as in the following example:


1 Answers

As an addendum to @KeithThompson's comment/answer...

Ada's officially supported C interface types are in Interfaces.C, and there's no extra-long int or unsigned in there (in the 2005 version. Is the 2012 version official yet?).

You did the right thing to work around it. If your compiler didn't support that, more drastic measures will have to be taken.

The first obvious thing to try is to pass the 64-bit int by reference. That will require changes on the C side though.

I know C/C++ TIME structs tend to be 64-bit values, defined as unioned structs. So what you could do is define an Ada record to mimic one of those C structs, make sure it gets laid out the way C would (eg: with record representation and size clauses), and then make that object what your imported routine uses for its parameter.

After that you'll have to pull nasty parameter tricks. For example, you could try changing the Ada import's side of the parameter to a 64-bit float, unchecked_converting the actual parameter into a 64-bit float, and trying to pass it that way. The problem there is that a lot of CPU's pass floats in different registers than ints. So that likely won't work, and if it does it most certianly isn't portable.

There may well be other ways to fake it out, if you figure out how your compiler's CPP calling convention works. For example, if it uses two adajacent 32-bit registers to pass 64-bit ints, you could split your Ada 64-bit int into two and pass it in two parameters on the Ada side. If it passes 64-bit values by reference, you could just tell the Ada side that you're passing a pointer to your U64. Again, these solutions won't be portable, but they would get you going.

like image 140
T.E.D. Avatar answered Oct 06 '22 00:10

T.E.D.