comp.lang.ada
 help / color / mirror / Atom feed
* Returning data from Ada to C
@ 2005-05-03 23:49 igor.kh
  2005-05-04  4:49 ` Jeffrey Carter
  0 siblings, 1 reply; 15+ messages in thread
From: igor.kh @ 2005-05-03 23:49 UTC (permalink / raw)


I want to make use of an Ada package from some C code. I already have
something that does almost what I want, but I need to figure out how to
return some data from Ada to C. I've never worked with Ada before, so
please pardon my ignorance.

Here's the setup. I have a C file:

---- main.c ----
#include <stdio.h>

extern void adainit();
extern void adafinal();
extern void _ada_phc_direct_solver ( ..., int *rcnt, double **solvec );

int main ()
{
  int rcnt;
  double *solvec;
  int i, j, n;

  /* Do some initializations. */
  ...

  /* I want the Ada code to store a pointer in `solvec'. */
  adainit();
  _ada_phc_direct_solver(..., &rcnt, &solvec);
  adafinal();
  /* BTW, is it OK to use Ada allocated memory after `adafinal()'? */

  /* Print results. */
  printf ("Root count: %d\n", rcnt);
  printf ("Roots: Re Im\n");
  for (i=0; i<rcnt; i++)
  {
    for (j=0; j<n; j++)
      printf ("%f %f\n", solvec[rcnt*n+2*j], solvec[rcnt*n+2*j+1]);
    printf ("\n");
  }

  return 0;
}
----------------

The Ada package uses its own suite of types to interface to C. I'll try
to provide their definitions as I understand them. The Ada side of this
looks like this:

---- phc_direct_solver.adb ----
procedure phc_direct_solver (..., rcnt : out integer;
		             solvec : out C_dblarrs.Pointer ) is

-- I'm not really sure how C_dblarrs.Pointer is defined, the closest
-- definition I can find is
--
--  type C_Double_Array is
--    array ( Interfaces.C.size_t range <> ) of aliased
Interfaces.C.double;
--
--  package C_DblArrs is
--    new Interfaces.C.Pointers(Interfaces.C.size_t,
--                              Interfaces.C.double,
--                              C_Double_Array,0.0);
--
-- Perhaps I should be using another type, but I don't know which one.

  rc : integer;
  sols : C_Double_Array; -- This is probably wrong, but `sols' will be
                         -- a C_Double_Array of some size.

begin
-- Calculate `rc' and `sols'.
  ...

-- Now I want to return `rcnt' and `sols'
  rcnt := rc;                -- This is the easy part.
  solvec := ???              -- What goes here?

end phc_direct_solver;
-------------------------------

Basically, the Ada code creates an array which I want pass back to the
C
code through a pointer. Unfortunately, I'm not familiar enough with Ada
figure out how to do that. Any help or suggestions would be
appreciated.

A related question. I'm using GNAT as the compiler. I read the section
in the documentation about linking a main C program with Ada auxiliary
Ada code. But it looks like the linking can only be done with gnatlink
at the final stage, when the executable is created. Is there a way to
compile the Ada code directly into a .o or .so object file that can be
linked normally with gcc?

Thanks in advance.

Igor

P.S.: For those who are curious, I'm trying to make use of PHCpack[1]
to
solve a system of polynomial equations. I'm working from the existing
example ts_phc_solver.c.

[1] http://www2.math.uic.edu/~jan/download.html




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-03 23:49 Returning data from Ada to C igor.kh
@ 2005-05-04  4:49 ` Jeffrey Carter
  2005-05-04 13:45   ` Igor Khavkine
  2005-05-16  4:35   ` Dave Thompson
  0 siblings, 2 replies; 15+ messages in thread
From: Jeffrey Carter @ 2005-05-04  4:49 UTC (permalink / raw)


igor.kh@gmail.com wrote:
>   /* BTW, is it OK to use Ada allocated memory after `adafinal()'? */

No.

>   sols : C_Double_Array; -- This is probably wrong, but `sols' will be
>                          -- a C_Double_Array of some size.

This won't compile. C_Double_Array is an unconstrained array type. 
Objects must be constrained. You probably need

Sols : aliased C_Double_Array (<your constraint here);

> -- Now I want to return `rcnt' and `sols'
>   rcnt := rc;                -- This is the easy part.
>   solvec := ???              -- What goes here?

Solvec := Sols'Unchecked_Access;

-- 
Jeff Carter
"You tiny-brained wipers of other people's bottoms!"
Monty Python & the Holy Grail
18



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-04  4:49 ` Jeffrey Carter
@ 2005-05-04 13:45   ` Igor Khavkine
  2005-05-04 13:58     ` Alex R. Mosteo
  2005-05-06  3:36     ` Jeffrey Carter
  2005-05-16  4:35   ` Dave Thompson
  1 sibling, 2 replies; 15+ messages in thread
From: Igor Khavkine @ 2005-05-04 13:45 UTC (permalink / raw)


Thanks for the quick reply.

On 2005-05-04, Jeffrey Carter <spam@spam.com> wrote:
> igor.kh@gmail.com wrote:
>>   /* BTW, is it OK to use Ada allocated memory after `adafinal()'? */
>
> No.

Ok, that's good to know. Also, will I be able to free Ada allocated
memory with the standard C library `free()'? For example, what do I do if
I want to free the storage pointed to by `solvec' below?

>>   sols : C_Double_Array; -- This is probably wrong, but `sols' will be
>>                          -- a C_Double_Array of some size.
>
> This won't compile. C_Double_Array is an unconstrained array type. 
> Objects must be constrained. You probably need
>
> Sols : aliased C_Double_Array (<your constraint here);
>
>> -- Now I want to return `rcnt' and `sols'
>>   rcnt := rc;                -- This is the easy part.
>>   solvec := ???              -- What goes here?
>
> Solvec := Sols'Unchecked_Access;

Great! Now, what type will `Solvec' have? I presume that GNAT will bark at
me if I use the wrong type.

Thanks.

Igor



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-04 13:45   ` Igor Khavkine
@ 2005-05-04 13:58     ` Alex R. Mosteo
  2005-05-06  3:36     ` Jeffrey Carter
  1 sibling, 0 replies; 15+ messages in thread
From: Alex R. Mosteo @ 2005-05-04 13:58 UTC (permalink / raw)


Igor Khavkine wrote:
> Thanks for the quick reply.
> 
> On 2005-05-04, Jeffrey Carter <spam@spam.com> wrote:
> 
>>igor.kh@gmail.com wrote:
>>
>>>  /* BTW, is it OK to use Ada allocated memory after `adafinal()'? */
>>
>>No.
> 
> 
> Ok, that's good to know. Also, will I be able to free Ada allocated
> memory with the standard C library `free()'? For example, what do I do if
> I want to free the storage pointed to by `solvec' below?

I'd export a new Ada procedure for this purpose, so you keep all memory 
management in the Ada side. Even if gnat uses malloc internally I guess 
this is safer.

> 
> 
>>>  sols : C_Double_Array; -- This is probably wrong, but `sols' will be
>>>                         -- a C_Double_Array of some size.
>>
>>This won't compile. C_Double_Array is an unconstrained array type. 
>>Objects must be constrained. You probably need
>>
>>Sols : aliased C_Double_Array (<your constraint here);
>>
>>
>>>-- Now I want to return `rcnt' and `sols'
>>>  rcnt := rc;                -- This is the easy part.
>>>  solvec := ???              -- What goes here?
>>
>>Solvec := Sols'Unchecked_Access;
> 
> 
> Great! Now, what type will `Solvec' have? I presume that GNAT will bark at
> me if I use the wrong type.
> 
> Thanks.
> 
> Igor



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-04 13:45   ` Igor Khavkine
  2005-05-04 13:58     ` Alex R. Mosteo
@ 2005-05-06  3:36     ` Jeffrey Carter
  2005-05-07 22:12       ` igor.kh
  1 sibling, 1 reply; 15+ messages in thread
From: Jeffrey Carter @ 2005-05-06  3:36 UTC (permalink / raw)


Igor Khavkine wrote:

> Ok, that's good to know. Also, will I be able to free Ada allocated
> memory with the standard C library `free()'? For example, what do I do if
> I want to free the storage pointed to by `solvec' below?

No. However, in the example, the memory isn't on the heap and shouldn't 
be deallocated.

> Great! Now, what type will `Solvec' have? I presume that GNAT will bark at
> me if I use the wrong type.

In Ada, it's a pointer to Double; to C it should look like a pointer to 
double. You probably should declare your array type to be convention C, 
just to be on the safe side.

-- 
Jeff Carter
"From this day on, the official language of San Marcos will be Swedish."
Bananas
28



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-06  3:36     ` Jeffrey Carter
@ 2005-05-07 22:12       ` igor.kh
  2005-05-08  2:07         ` Jeffrey Carter
  2005-05-08  9:41         ` Martin Dowie
  0 siblings, 2 replies; 15+ messages in thread
From: igor.kh @ 2005-05-07 22:12 UTC (permalink / raw)


Jeffrey Carter wrote:
> Igor Khavkine wrote:

> > Great! Now, what type will `Solvec' have? I presume that GNAT will
> > bark at me if I use the wrong type.
>
> In Ada, it's a pointer to Double; to C it should look like a pointer
> to double. You probably should declare your array type to be
> convention C, just to be on the safe side.

I've tried to construct a simple example where this would work.
However, I am still failing. I can't get the types to match up. Below
are the files that I'm using. The exact error from gnat is:

hello_world.adb:18:19: expected type "Interfaces.C.Pointers.Pointer"
from instance at c_integer_arrays.ads:6

== c_integer_arrays.ads ================
with Interfaces.C; use Interfaces.C;
with Interfaces.C.Pointers;

package C_Integer_Arrays is
	type C_Integer_Array is array (size_t range <>) of aliased int;
	package C_IntArrs is
		new Interfaces.C.Pointers(size_t, int,
			C_Integer_Array, 0);
end C_Integer_Arrays;
========================================

== hello_world.ads =====================
with Interfaces.C; use Interfaces.C;
with C_Integer_Arrays; use C_Integer_Arrays;

procedure Hello_World ( i : in out integer; a_ptr : out
C_IntArrs.Pointer );
pragma Export (C, Hello_World);
========================================

== hello_world.adb =====================
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

with Interfaces.C; use Interfaces.C;
with C_Integer_Arrays; use C_Integer_Arrays;

procedure Hello_World ( i : in out integer;
	a_ptr : out C_IntArrs.Pointer ) is
	a : aliased array(0..2) of int;
	pragma Convention (C, a);
begin
	Put ("Hello world!");
	Put (i);
	i := 10;
	a(0) := 3;
	a(1) := 2;
	a(2) := 1;
	a_ptr := a'Unchecked_Access;
end Hello_World;
========================================

== hello.c =============================
#include <stdio.h>

void adainit();
void adafinal();
void hello_world(int *i, int **a_ptr);

int main()
{
	int i = 1;
	int *a_ptr;

	printf ("Calling Ada...\n");

	adainit();
	hello_world(&i, &a_ptr);

	printf ("...done\n");
	printf ("Returned i = %d\n", i);
	for (i=0; i<3; i++)
		printf ("a_ptr[%d] = %d\n", i, a_ptr[i]);

	adafinal();

	return 0;
}
========================================

What am I missing to make this work?

Thanks in advance.

Igor




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-07 22:12       ` igor.kh
@ 2005-05-08  2:07         ` Jeffrey Carter
  2005-05-08 19:58           ` Jeffrey Carter
  2005-05-08  9:41         ` Martin Dowie
  1 sibling, 1 reply; 15+ messages in thread
From: Jeffrey Carter @ 2005-05-08  2:07 UTC (permalink / raw)


igor.kh@gmail.com wrote:
> 
>>Igor Khavkine wrote:
> 
> 	type C_Integer_Array is array (size_t range <>) of aliased int;

This is an array type.

> 	a : aliased array(0..2) of int;

This is a different array type.

> 	a_ptr := a'Unchecked_Access;

This is not a pointer to C_Integer_Array. It's a pointer to the 
anonymous array type in the declaration of A.

-- 
Jeff Carter
"So if I understand 'The Matrix Reloaded' correctly, the Matrix is
basically a Microsoft operating system--it runs for a while and
then crashes and reboots. By design, no less. Neo is just a
memory leak that's too hard to fix, so they left him in ... The
users don't complain because they're packed in slush and kept
sedated."
Marin D. Condic
65



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-07 22:12       ` igor.kh
  2005-05-08  2:07         ` Jeffrey Carter
@ 2005-05-08  9:41         ` Martin Dowie
  2005-05-08 14:55           ` Ludovic Brenta
  1 sibling, 1 reply; 15+ messages in thread
From: Martin Dowie @ 2005-05-08  9:41 UTC (permalink / raw)


igor.kh@gmail.com wrote:
[snip]
> == hello.c =============================
> #include <stdio.h>
> 
> void adainit();
> void adafinal();
> void hello_world(int *i, int **a_ptr);
> 
> int main()
> {
> 	int i = 1;
> 	int *a_ptr;
> 
> 	printf ("Calling Ada...\n");
> 
> 	adainit();
> 	hello_world(&i, &a_ptr);
> 
> 	printf ("...done\n");
> 	printf ("Returned i = %d\n", i);
> 	for (i=0; i<3; i++)
> 		printf ("a_ptr[%d] = %d\n", i, a_ptr[i]);
> 
> 	adafinal();
> 
> 	return 0;
> }
> ========================================
> 
> What am I missing to make this work?

Don't you have to allocate some memory for this array before passing it 
around?...

Cheers

-- Martin



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-08  9:41         ` Martin Dowie
@ 2005-05-08 14:55           ` Ludovic Brenta
  2005-05-08 14:58             ` Ludovic Brenta
  0 siblings, 1 reply; 15+ messages in thread
From: Ludovic Brenta @ 2005-05-08 14:55 UTC (permalink / raw)


Martin Dowie writes:
> wrote:
> [snip]
>> == hello.c =============================
>> #include <stdio.h>
>> void adainit();
>> void adafinal();
>> void hello_world(int *i, int **a_ptr);
>> int main()
>> {
>> 	int i = 1;
>> 	int *a_ptr;
>> 	printf ("Calling Ada...\n");
>> 	adainit();
>> 	hello_world(&i, &a_ptr);
>> 	printf ("...done\n");
>> 	printf ("Returned i = %d\n", i);
>> 	for (i=0; i<3; i++)
>> 		printf ("a_ptr[%d] = %d\n", i, a_ptr[i]);
>> 	adafinal();
>> 	return 0;
>> }
>> ========================================
>> What am I missing to make this work?
>
> Don't you have to allocate some memory for this array before passing
> it around?...
>
> Cheers
>
> -- Martin

If I understand the design correctly, Hello_World is supposed to do
the allocation, but from the previous post it looks like the
allocation takes place on the stack, and then Hello_World sets a_ptr
using 'Unchecked_Access.

The OP should rewrite Hello_World like this:

procedure Hello_World (I : in out Integer;
                       A_Ptr : out C_IntArrs.Pointer) is
   type Array_Access is access C_Integer_Arrays.C_Integer_Array;
   Result : Array_Access := new C_Integer_Arrays.C_Integer_Array'
          (0 => 3, 1 => 2, 2 => 1);
begin
   return Result (Result'First)'Access;
end Hello_World;

Beware that 

- main() must have some way of knowing the length of the array.

- main() must deallocate the array, preferably using an Ada procedure
  because the array was allocated using the Ada default storage pool.

Perhaps it is better indeed if main() allocates the memory for the
array and just passes it to Hello_World.

-- 
Ludovic Brenta.




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-08 14:55           ` Ludovic Brenta
@ 2005-05-08 14:58             ` Ludovic Brenta
  2005-05-09 22:49               ` igor.kh
  0 siblings, 1 reply; 15+ messages in thread
From: Ludovic Brenta @ 2005-05-08 14:58 UTC (permalink / raw)


Ludovic Brenta writes:
> procedure Hello_World (I : in out Integer;
>                        A_Ptr : out C_IntArrs.Pointer) is
>    type Array_Access is access C_Integer_Arrays.C_Integer_Array;
>    Result : Array_Access := new C_Integer_Arrays.C_Integer_Array'
>           (0 => 3, 1 => 2, 2 => 1);
> begin
>    return Result (Result'First)'Access;
     -- the above is wrong!
     A_Ptr := Result (Result'First)'Access; -- correct
> end Hello_World;

obviously.

-- 
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-08  2:07         ` Jeffrey Carter
@ 2005-05-08 19:58           ` Jeffrey Carter
  0 siblings, 0 replies; 15+ messages in thread
From: Jeffrey Carter @ 2005-05-08 19:58 UTC (permalink / raw)


Jeffrey Carter wrote:
> igor.kh@gmail.com wrote:
> 
>>     a_ptr := a'Unchecked_Access;
> 
> This is not a pointer to C_Integer_Array. It's a pointer to the 
> anonymous array type in the declaration of A.

Let me correct this statement:

This is not a pointer to Int, which is how A_Ptr is declared. It's a 
pointer to the anonymous array type in the declaration of A.

Not also that A is local to the Ada procedure, and will go away when the 
procedure returns, making A_Ptr a dangling reference.

-- 
Jeff Carter
"Now go away or I shall taunt you a second time."
Monty Python & the Holy Grail
07



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-08 14:58             ` Ludovic Brenta
@ 2005-05-09 22:49               ` igor.kh
  2005-05-10 12:48                 ` Ludovic Brenta
  0 siblings, 1 reply; 15+ messages in thread
From: igor.kh @ 2005-05-09 22:49 UTC (permalink / raw)


Ludovic Brenta wrote:
> Ludovic Brenta writes:
> > procedure Hello_World (I : in out Integer;
> >                        A_Ptr : out C_IntArrs.Pointer) is
> >    type Array_Access is access C_Integer_Arrays.C_Integer_Array;
> >    Result : Array_Access := new C_Integer_Arrays.C_Integer_Array'
> >           (0 => 3, 1 => 2, 2 => 1);
> > begin
> >    return Result (Result'First)'Access;
>      -- the above is wrong!
>      A_Ptr := Result (Result'First)'Access; -- correct
> > end Hello_World;
>
> obviously.

I had to use Unchecked_Access instead of Access (gnat complained
"non-local pointer cannot point to local object"), but it worked!

Thanks, everyone, for your help.

Igor




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-09 22:49               ` igor.kh
@ 2005-05-10 12:48                 ` Ludovic Brenta
  0 siblings, 0 replies; 15+ messages in thread
From: Ludovic Brenta @ 2005-05-10 12:48 UTC (permalink / raw)


 writes:
> Ludovic Brenta wrote:
>> Ludovic Brenta writes:
>> > procedure Hello_World (I : in out Integer;
>> >                        A_Ptr : out C_IntArrs.Pointer) is
>> >    type Array_Access is access C_Integer_Arrays.C_Integer_Array;
>> >    Result : Array_Access := new C_Integer_Arrays.C_Integer_Array'
>> >           (0 => 3, 1 => 2, 2 => 1);
>> > begin
>> >    return Result (Result'First)'Access;
>>      -- the above is wrong!
>>      A_Ptr := Result (Result'First)'Access; -- correct
>> > end Hello_World;
>>
>> obviously.
>
> I had to use Unchecked_Access instead of Access (gnat complained
> "non-local pointer cannot point to local object"), but it worked!

If you move the type declaration outside of the procedure, then
'Access becomes legal.  The best would be to declare Array_Access in
C_Integer_Arrays.

-- 
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-04  4:49 ` Jeffrey Carter
  2005-05-04 13:45   ` Igor Khavkine
@ 2005-05-16  4:35   ` Dave Thompson
  2005-05-16  5:03     ` Jeffrey Carter
  1 sibling, 1 reply; 15+ messages in thread
From: Dave Thompson @ 2005-05-16  4:35 UTC (permalink / raw)


On Wed, 04 May 2005 04:49:09 GMT, Jeffrey Carter <spam@spam.com>
wrote:

> igor.kh@gmail.com wrote:
> >   /* BTW, is it OK to use Ada allocated memory after `adafinal()'? */
> 
> No.
> 
> >   sols : C_Double_Array; -- This is probably wrong, but `sols' will be
> >                          -- a C_Double_Array of some size.
> 
> This won't compile. C_Double_Array is an unconstrained array type. 
> Objects must be constrained. You probably need
> 
> Sols : aliased C_Double_Array (<your constraint here);
> 
> > -- Now I want to return `rcnt' and `sols'
> >   rcnt := rc;                -- This is the easy part.
> >   solvec := ???              -- What goes here?
> 
> Solvec := Sols'Unchecked_Access;

Not if Sols is a procedure-local variable, as in the OP's code, and
the (C) caller intends to dereference the resulting pointer, as it
does. For the storage to remain valid for the caller to access, it
needs either to be (in a package) at library level, or dynamically
allocated in Ada by 'new' (and some provision e.g. another callable
Ada routine for deallocating it if necessary) or by hand-built Ada
call to C's malloc in which case the C code can safely free() it.

These considerations are the same if the called code were C instead of
Ada, except that C has file-scope static instead of package, and the
additional very slightly different option of procedure-local static.

- David.Thompson1 at worldnet.att.net



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Returning data from Ada to C
  2005-05-16  4:35   ` Dave Thompson
@ 2005-05-16  5:03     ` Jeffrey Carter
  0 siblings, 0 replies; 15+ messages in thread
From: Jeffrey Carter @ 2005-05-16  5:03 UTC (permalink / raw)


Dave Thompson wrote:

> Not if Sols is a procedure-local variable, as in the OP's code, and
> the (C) caller intends to dereference the resulting pointer, as it
> does. For the storage to remain valid for the caller to access, it
> needs either to be (in a package) at library level, or dynamically
> allocated in Ada by 'new' (and some provision e.g. another callable
> Ada routine for deallocating it if necessary) or by hand-built Ada
> call to C's malloc in which case the C code can safely free() it.

This was discussed in another message in the thread.

-- 
Jeff Carter
"You've got the brain of a four-year-old boy,
and I bet he was glad to get rid of it."
Horse Feathers
47



^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2005-05-16  5:03 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-05-03 23:49 Returning data from Ada to C igor.kh
2005-05-04  4:49 ` Jeffrey Carter
2005-05-04 13:45   ` Igor Khavkine
2005-05-04 13:58     ` Alex R. Mosteo
2005-05-06  3:36     ` Jeffrey Carter
2005-05-07 22:12       ` igor.kh
2005-05-08  2:07         ` Jeffrey Carter
2005-05-08 19:58           ` Jeffrey Carter
2005-05-08  9:41         ` Martin Dowie
2005-05-08 14:55           ` Ludovic Brenta
2005-05-08 14:58             ` Ludovic Brenta
2005-05-09 22:49               ` igor.kh
2005-05-10 12:48                 ` Ludovic Brenta
2005-05-16  4:35   ` Dave Thompson
2005-05-16  5:03     ` Jeffrey Carter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox