From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,8a3d369650eccae6 X-Google-Attributes: gid103376,public From: "Weston T. Pan" Subject: Maybe this can shed some light( Re: Interface with C Date: 1999/05/20 Message-ID: <3744F1BC.B2315B4E@usc.edu> X-Deja-AN: 480409663 Content-Transfer-Encoding: 7bit References: <7i1n9t$6fs@beast.connix.com> X-Accept-Language: en Content-Type: text/plain; charset=us-ascii Organization: University of Southern California, Los Angeles, CA Mime-Version: 1.0 Newsgroups: comp.lang.ada Date: 1999-05-20T00:00:00+00:00 List-Id: 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: 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.