comp.lang.ada
 help / color / mirror / Atom feed
* Interface with C
@ 1999-05-20  0:00 Deepak Haste
  1999-05-20  0:00 ` Maybe this can shed some light( " Weston T. Pan
  0 siblings, 1 reply; 3+ messages in thread
From: Deepak Haste @ 1999-05-20  0:00 UTC (permalink / raw)


Hello,

I am implementing an ADA routine that interfaces with a Win32 C-library on
an NT. I am trying to import an array into an ADA procedure from a
C -function call.

The C function looks like this

 > DllImport int GetKnownBadComponents_RT(int **bad_components,  ...);

A call to this function would give us the address of the array.

****************************************************************************
***
The corresponding ADA binding looks like this :

 >  type components is array(Integer range <>) of Integer;

------------------------------------------------
>   pragma convention(C,components);
------------------------------------------------

 >  type components_ptr is access components;

 >  function GetKnownBadComponents_RT(bad_components_ptr : in
components_ptr; ..) return Integer;
                                                                           -
- function prototype

****************************************************************************
*
While calling this function from an ada procedure I do:

 >     badcomponents_ptr : components_ptr := new components(0 .. 9);
                                                                           -
- initialized to point to a 10 component array

 >     ret_code := GetKnownBadComponents_RT(badcomponents_ptr,...);
                                                                           -
- the actual function call

 >     for Item in badcomponents_ptr.all'range loop
 >           Put(Integer'Image(badcomponents_ptr.all(Item)));
 >     end loop;
                                                                           -
- display array elements

****************************************************************************
*

Now, I know that the C function does not pass array of size greater than 5.
Also, the inclusion/exclusion of the pragma convention makes it behave
differently. When pragma is excluded, the procedure gives constraint error
at the function call. When included, I get the first element correctly.
However the display loop goes infinite giving out the rest as garbage. Any
suggestions will be greatly appreciated.

Thanks,
Deepak Haste.






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

* Maybe this can shed some light( Re: Interface with C
  1999-05-20  0:00 Interface with C Deepak Haste
@ 1999-05-20  0:00 ` Weston T. Pan
  1999-05-22  0:00   ` Robert Dewar
  0 siblings, 1 reply; 3+ messages in thread
From: Weston T. Pan @ 1999-05-20  0:00 UTC (permalink / raw)


Deepak Haste wrote:
> 
> Hello,
> 
> I am implementing an ADA routine that interfaces with a Win32 C-library on
> an NT. I am trying to import an array into an ADA procedure from a
> C -function call.
> 
> The C function looks like this
> 
>  > DllImport int GetKnownBadComponents_RT(int **bad_components,  ...);
> 
> A call to this function would give us the address of the array.
> 
> ****************************************************************************
> ***
> The corresponding ADA binding looks like this :
> 
>  >  type components is array(Integer range <>) of Integer;
> 
> ------------------------------------------------
> >   pragma convention(C,components);
> ------------------------------------------------
> 
>  >  type components_ptr is access components;
> 
>  >  function GetKnownBadComponents_RT(bad_components_ptr : in
> components_ptr; ..) return Integer;
>                                                                            -
> - function prototype
> 

Hi,

I saved this some time ago. I believe it may help.


[Begin paste]

Subject:      Re: System.Address_To_Access_Conversions
From:         dewar@cs.nyu.edu (Robert Dewar)
Date:         1995/09/02
Message-ID:   <dewar.810092305@schonberg>
Newsgroups:   comp.lang.ada
[More Headers]
[Subscribe to comp.lang.ada]

Article Segment 1 of 2
(Get All 2 Segments)

Sean McNeil asks

>While looking into some problems with the xbind package and some other
>code I didn't write, I discovered that GNAT has apparantly gone to (or
>always used) fat pointers for unconstrained access types.  This caused
>some of the code to fail on unchecked_conversions, so I looked into
>System.Address_To_Access_Conversions.
>
>It appears that it'll take an Object with an indefinate subtype which
>is what I want, but I could not figure out how a compiler would implement
>such a thing.  I thought maybe it could take the address in the To_Address
>function and knowing where the dicriminants or array info is located
>could the reconstruct an access to the object, but that means the To_Access
>function would have to do a lot of work and might just be too complicated
>to make it worthwhile.  Further, with a fat pointer I assume this information
>is not available in some instances.
>
>I figure that just about everyone will place an allowable restriction on
>instantiations of Address_To_Access_Conversions and not worry about it.
>Was the (<>) just overkill or is there the possibility that someone will
>implement this?

This is an area which certainly confuses people, so here is an attempt
to
clarify some issues.

There are three methods of dealing with pointers to unconstrained arrays
that I am aware of. I will call these the "fat pointer" method,
"adjoined
descriptor" method, and "indirect" method. These are not standard terms,
just coinages for this message.
The issue of course is that a pointer to an unconstrained array must
somehow
encode both the location of the data and the bounds.

The Fat Pointer Method (used by GNAT currently)
-----------------------------------------------

A pointer to an unconstrained array is actually two pointers (and hence
twice as big ("fat") as a normal pointer). One of these pointers points
to the data, and one points to the bounds.

The Adjoined Descriptor Method (used by several compilers)
----------------------------------------------------------

The bounds for an array are always placed just behind the data. This
means
that if you have a pointer to the data, you can look just behind it and
find
the bounds. So you can use a normal length ("thin") pointer. One
possible
issue: what about slices? Well Ada has a restriction that forbids
pointers
to slices, so that solves that (this restriction is not an accident :-)
Of
course fat pointers *could* handle such pointers, but they never arise.
One
thing this *does* mean is that procedure parameters passed by reference
cannot be passed simply as normal pointers, but no one said they had to
be!

The Indirect Method (used I think by the RR compiler)
-----------------------------------------------------

The pointer is a pointer to a descriptor that contains pointers to the
data and to the bounds separately, or perhaps the desctiptor contains
a data pointer and the bounds themselves. This is also a thin pointer
approach.

Comparison of the Methods
-------------------------

There are time/space/simplicity/funcitonality tradeoffs between these
methods. The following is a list of advantages and disadvantages, not
necessarily complete:

  1. Fat pointers are potentially more efficient in time, particularly
     since they can have direct virtual origin data pointers
(eliminating
     the need for subtracting the lower bound when referencing data).
The
     adjoined descriptor method does not allow use of virtual origins.

  2. Fat pointers allow procedure parameters to be passed as normal
     pointers. This is not important for a user but simplifies the
     implementation.

  3. Thin pointers (both cases) take less space

  4. Thin pointers are the same size as other addresses and pointers,
and
     allow easy unchecked conversion (maybe see below!) and allow easier
     interface to foreign pointers (maybe, see below!)

  5. The indirect method involves extra memory references, and also has
     surprises in unchecked conversions (you end up pointing to the
     descriptor instead of the data).
  6. Fat pointers cause embarassment with Taft Amendment types (those
     completed in the body), where you don't know at the right time
     whether to make the pointer thin or fat (GNAT doesn't yet implement
     Taft Amendment types completed with an unconstrained array,
     surprise :-)

There are probably other issues, but this gives a flavor of some of the
considerations.


Unchecked Conversion Issues
---------------------------

If you unchecked convert a pointer to an unconstrained array to a single
length address, this may or may not work. It will not work in the fat
pointer case unless the compiler special cases it (GNAT does not), and
will definitely not work in the indirect approach. It *will* work if
your compiler uses the adjoined pointer method. Many programs take
advantage of this, and are hence non-portable.

The proper portable way of taking the address of an array is to take
the address of the first element, i.e. don't work with the unconstrained
pointer, or its address, but rather with an access or pointer to the
first element of the array. This is much more portable. Dave Emery has
explored this in some detail in his writings on the use of addresses.

Now what about the other way, taking an address and doing an unchecked
conversion to an unconstrained pointer, or, really the same thing,
taking
a C record, and calling a C pointer access-to-string or something
similar
on the Ada side.

THIS IS VERY DANGEROUS!

Why? well where are the bounds supposed to come from? The compiler is
not telepathic, it can't guess the bounds! In a compiler using the
adjoined descriptor method, this will sort of work, in that the data
pointer will be correct, but the bounds will be garbage.

But consider the following:

   Take a pointer to unconstrained
   Uncheck convert to address
   Uncheck back to pointer to unconstrained

      This will work OK with the adjoined descriptor method
        and with the indirect method, but not the fat pointer method

   Take a pointer to unconstrained
   Uncheck convert to address
   Reference the data using this address in a C program
   Uncheck back to pointer to unconstrained

      This will work ONLY in the adjoined desctiptor method

Note that the address to access conversions package allows these kind
of operations, even though they may well not work, and in some cases
can't possibly work. I objected to allowing these features to convert
an address to a pointer-to-unconstrained, on the grounds that it cannot
always work, and is dangerous. However, the design team decided to
retain
it because of the fact that with some implementation approaches it may
work some of the time. OK, but that does not stop it from being
dangerous.
BE VERY CAREFUL.

I think the best representation of a C pointer to string is the Ada type

   type Unknown_String is array (Natural) of Character;
   type C_Pointer is acess Unknown_String;

Using this type really reminds an Ada programmer that the bounds are
the responsibility of the programmer and not being taken care of by
the compiler.

The other option of course is to use the routines in the C interface
and not operate at this low level at all!

[end paste]


> ****************************************************************************
> *
> While calling this function from an ada procedure I do:
> 
>  >     badcomponents_ptr : components_ptr := new components(0 .. 9);
>                                                                            -
> - initialized to point to a 10 component array
> 
>  >     ret_code := GetKnownBadComponents_RT(badcomponents_ptr,...);
>                                                                            -
> - the actual function call
> 
>  >     for Item in badcomponents_ptr.all'range loop
>  >           Put(Integer'Image(badcomponents_ptr.all(Item)));
>  >     end loop;
>                                                                            -
> - display array elements
> 
> ****************************************************************************
> *
> 
> Now, I know that the C function does not pass array of size greater than 5.
> Also, the inclusion/exclusion of the pragma convention makes it behave
> differently. When pragma is excluded, the procedure gives constraint error
> at the function call. When included, I get the first element correctly.
> However the display loop goes infinite giving out the rest as garbage. Any
> suggestions will be greatly appreciated.
> 
> Thanks,
> Deepak Haste.




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

* Re: Maybe this can shed some light( Re: Interface with C
  1999-05-20  0:00 ` Maybe this can shed some light( " Weston T. Pan
@ 1999-05-22  0:00   ` Robert Dewar
  0 siblings, 0 replies; 3+ messages in thread
From: Robert Dewar @ 1999-05-22  0:00 UTC (permalink / raw)


In article <3744F1BC.B2315B4E@usc.edu>,
  "Weston T. Pan" <westonpa@usc.edu> wrote:

To clarify, GNAT uses either fat pointers or the adjoined
descriptor method. The default is fat pointers, but you
can override this with a size clause.

Note that it is possible in GNAT to generate pointers to
slices, using 'Unrestricted_Access. This is of course not
a portable feature!


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---




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

end of thread, other threads:[~1999-05-22  0:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-05-20  0:00 Interface with C Deepak Haste
1999-05-20  0:00 ` Maybe this can shed some light( " Weston T. Pan
1999-05-22  0:00   ` Robert Dewar

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