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,FREEMAIL_FROM autolearn=unavailable autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!feeder.eternal-september.org!aioe.org!.POSTED!not-for-mail From: Victor Porton Newsgroups: comp.lang.ada Subject: Re: Convert between C "void*" pointer and an access Date: Thu, 12 Oct 2017 04:01:19 +0300 Organization: Aioe.org NNTP Server Message-ID: References: NNTP-Posting-Host: 8U0x309/ia0QUzusgm/krA.user.gioia.aioe.org Mime-Version: 1.0 Content-Type: text/plain; charset="ISO-8859-1" Content-Transfer-Encoding: 7Bit X-Complaints-To: abuse@aioe.org User-Agent: KNode/4.14.10 X-Notice: Filtered by postfilter v. 0.8.2 Xref: news.eternal-september.org comp.lang.ada:48437 Date: 2017-10-12T04:01:19+03:00 List-Id: Victor Porton wrote: > Victor Porton wrote: > >> Victor Porton wrote: >> >>> What is the right way to convert between C "void*" pointer and an access >>> to a tagged or class-wide type? >>> >>> Ada.Unchecked_Conversion seems to be what I need, but the access type >>> may be "fat" and thus have another format than void*. >>> >>> I caught myself doing such unchecked conversions, but now I feel I did >>> an error. >>> >>> For example, let >>> >>> type X_Type is abstract tagged null record; >>> >>> How to store X_Type'Class pointer in "void*" and convert them back and >>> forth? >> >> It seems I've found a right solution of my problem. (Check if Ada RM >> warrants that it works with every compiler!) >> >> Well, why it is not a standard package?! Why I need to invent something >> "smart" every time I need to code? > > The package body was with a bug. Here there is corrected code: [snip] (see code above in the thread) Now I will prove that it works without errors with every conforming compilers. The below will describe how my package Convert_Void works. If in doubt, consult the package source code. First I should formulate the problem exactly: Having an Ada object (we can restrict to tagged and class-wide types and benefit from the fact that such objects 'Address "should produce a useful result" (RM 13.3.16)), we need to transform it to C void pointer and pass to C code; the C code should be able to call Ada code (e.g. through subprogram access) and pass the pointer back and the Ada code should be able to work with the original Ada object. In other words, we need to define two functions: To_Pointer which converts all access values for a certain type (tagged or class-wide, at least) into void pointers and To_Access which converts void pointers obtained by To_Pointer back into the original access value. In other words, we need two mutually inverse bijections between every set of values of 'Unchecked_Access of values of a type (tagged or class-wide, at least) and a subset of C void pointers. We also need map null access to NULL pointer and vice versa. We will use chars_ptr from Interfaces.C.Strings to represent void pointers. It is valid because C11, 6.2.5, 28 (draft N1548): "A pointer to void shall have the same representation and alignment requirements as a pointer to a character type." This problem is solved in my generic package Convert_Void: -- "with" and "use" skipped generic type Object(<>) is limited private; package Convert_Void is package Address_Conversions is new System.Address_To_Access_Conversions(Object); subtype Object_Pointer is Address_Conversions.Object_Pointer; function To_Access (Void_Pointer: chars_ptr) return Object_Pointer; function To_C_Pointer (Pointer: Object_Pointer) return chars_ptr; end Convert_Void; We define in Convert_Void body: type My_Char_Pointer is access all char with Convention=>C; package Char_Address_Conversions is new System.Address_To_Access_Conversions(char); One of the steps of implementing the functions To_Pointer and To_Access is to convert between chars_ptr and My_Char_Pointer. This is trivially done with Ada.Unchecked_Conversion because they are by definition the same C type char* and thus have the same representation. So our task is reduced to conversion between My_Char_Pointer an Ada object access. We do this conversion (in both directions) like: Char_Address_Conversions.To_Pointer(Address_Conversions.To_Address(...)) Address_Conversions.To_Pointer(Char_Address_Conversions.To_Address(...)) The thing to prove is that this is an injective function from object pointers to My_Char_Pointer values and that backward conversion is really its inversion. But it is just my understanding of "The To_Pointer and To_Address subprograms convert back and forth between values of types Object_Pointer and Address." (RM 13.7.2 5/2) That null access are mapped into NULL pointers and vice versa is left as an exercise to the reader. -- Victor Porton - http://portonvictor.org