* Interfacing to C without dynamic memory @ 2008-11-14 13:58 Maciej Sobczak 2008-11-14 20:35 ` Damien Carbonne 2008-11-14 23:13 ` Robert A Duff 0 siblings, 2 replies; 6+ messages in thread From: Maciej Sobczak @ 2008-11-14 13:58 UTC (permalink / raw) Hi, Consider a C (or C++) library that defines some type T with some functions operating on it. The type T can be a complex type, encapsulated in a struct or class. Assuming extern "C" interface, the library functions usually accept a pointer to T: struct T { // lots of interesting stuff }; void createT(T * object); void destroyT(T * object); void foo(T * object, int something); void bar(T * object, int something_else); In C and C++ it is possible to use objects of type T without allocating them dynamically, which would be otherwise mandated by an alternative interface: T * newT(); void deleteT(T * object); How would you approach wrapping such a library for Ada while retaining the requirement that dynamic memory is not obligatory (ie. with the original interface above)? My first ideas are: 1. Extract sizeof(T) at C level. 2. In Ada, create appropriately aligned: type T is System.Storage_Array (1 .. Size_Of_T); for T'Alignment use Appropriate_Alignment_Value; 3. Wrap imported C functions by passing to them the 'Address of T's instances. This way, users will be able to use T as any other value type, without resorting to dynamic memory. Does it make sense? Is there any better way? -- Maciej Sobczak * www.msobczak.com * www.inspirel.com Database Access Library for Ada: www.inspirel.com/soci-ada ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Interfacing to C without dynamic memory 2008-11-14 13:58 Interfacing to C without dynamic memory Maciej Sobczak @ 2008-11-14 20:35 ` Damien Carbonne 2008-11-15 1:12 ` Randy Brukardt 2008-11-14 23:13 ` Robert A Duff 1 sibling, 1 reply; 6+ messages in thread From: Damien Carbonne @ 2008-11-14 20:35 UTC (permalink / raw) Hi, I have never tried what you propose, but I think it should work. Of course, all fields of T should be initialized in C code (in createT, I guess). In Ada, you could also wrap the array in a record. That way, you could initialize everything to 0: type T is record Bytes : System.Storage_Array (...); end record; pragma Convention (C, T); + other pragma if necessary ... Make T private, or even limited private: Ada users should not have direct access to T fields. Also, you shouldn't need to use 'Address. By default, when you use C convention/import, structures and arrays are passed by address. Of course, as you don't have direct access to T fields, you need to provide all necessary functions to do that. So you would have: package XXX is type T is [limited] private; procedure Create (O : in out T); procedure Destroy (O : in out T); ... private type T is ... -- as your proposal ... pragma Import (C, Create, "CreateT"); pragma Import (C, Destroy, "DestroyT"); ... end XXX; Maciej Sobczak a �crit : > Hi, > > Consider a C (or C++) library that defines some type T with some > functions operating on it. > The type T can be a complex type, encapsulated in a struct or class. > Assuming extern "C" interface, the library functions usually accept a > pointer to T: > > struct T > { > // lots of interesting stuff > }; > > void createT(T * object); > void destroyT(T * object); > void foo(T * object, int something); > void bar(T * object, int something_else); > > In C and C++ it is possible to use objects of type T without > allocating them dynamically, which would be otherwise mandated by an > alternative interface: > > T * newT(); > void deleteT(T * object); > > How would you approach wrapping such a library for Ada while retaining > the requirement that dynamic memory is not obligatory (ie. with the > original interface above)? > > My first ideas are: > 1. Extract sizeof(T) at C level. > 2. In Ada, create appropriately aligned: > > type T is System.Storage_Array (1 .. Size_Of_T); > for T'Alignment use Appropriate_Alignment_Value; > > 3. Wrap imported C functions by passing to them the 'Address of T's > instances. > > This way, users will be able to use T as any other value type, without > resorting to dynamic memory. > > Does it make sense? Is there any better way? > > -- > Maciej Sobczak * www.msobczak.com * www.inspirel.com > > Database Access Library for Ada: www.inspirel.com/soci-ada ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Interfacing to C without dynamic memory 2008-11-14 20:35 ` Damien Carbonne @ 2008-11-15 1:12 ` Randy Brukardt 0 siblings, 0 replies; 6+ messages in thread From: Randy Brukardt @ 2008-11-15 1:12 UTC (permalink / raw) ... > 3. Wrap imported C functions by passing to them the 'Address of T's > instances. You were fine up to here. But there is no reason at all to do this; you can use 'Access and a general access type with the appropriate convention; 'Access and an anonymous access type, or best of all, just plain parameters (which will be passed by reference for routines with the C convention). An Ada 95 or newer program that uses System.Address outside of address clauses is broken, IMHO. There are many safer ways to do those things. (And avoiding access types is good, too.) For Claw, most of the interfaces use locally declared records with the StdCall convention (and all of the components defined by Win32), and usually normal 'in' and 'in out' parameters. The only access parameters that we used was in functions that modified some of their arguments (and that was only because of Ada's broken rule against 'in out' parameters in functions). Randy. Randy. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Interfacing to C without dynamic memory 2008-11-14 13:58 Interfacing to C without dynamic memory Maciej Sobczak 2008-11-14 20:35 ` Damien Carbonne @ 2008-11-14 23:13 ` Robert A Duff 2008-11-15 11:52 ` Samuel Tardieu 1 sibling, 1 reply; 6+ messages in thread From: Robert A Duff @ 2008-11-14 23:13 UTC (permalink / raw) Maciej Sobczak <see.my.homepage@gmail.com> writes: > My first ideas are: > 1. Extract sizeof(T) at C level. > 2. In Ada, create appropriately aligned: > > type T is System.Storage_Array (1 .. Size_Of_T); > for T'Alignment use Appropriate_Alignment_Value; Makes sense. You could write a C program that #include's the relevant .h file, and prints out an Ada package spec containing the above Ada code. You could run this as part of your build scripts. - Bob ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Interfacing to C without dynamic memory 2008-11-14 23:13 ` Robert A Duff @ 2008-11-15 11:52 ` Samuel Tardieu 2008-11-16 21:31 ` Maciej Sobczak 0 siblings, 1 reply; 6+ messages in thread From: Samuel Tardieu @ 2008-11-15 11:52 UTC (permalink / raw) >>>>> "Bob" == Robert A Duff <bobduff@shell01.TheWorld.com> writes: Bob> Makes sense. You could write a C program that #include's the Bob> relevant .h file, and prints out an Ada package spec containing Bob> the above Ada code. You could run this as part of your build Bob> scripts. Doing it properly is quite painful when you cross-compile, you have to play dirty unportable tricks such as parsing the assembly file output by the compiler to extract the value. This is the way I originally did it in GLADE, it was then used to generate GNAT.Sockets.Constants, but as you know AdaCore recently switched to parsing the C compiler output, which was possible because the GCC C compiler (native or cross) is always available when building the runtime. Note that you can also do it at run time, even if it costs a few more cycles to allocate the object, by taking advantage of C ability to resolve "sizeof" into a static value at compile time. This obliviates the cross-compilation issues. Here is an example (t.c, t_interface.ads and test.adb): (note that in real life, one would include the header defining "struct T" instead of exporting "T_size" in the same file) /* t.c */ #include <stdlib.h> struct T { char a; void *b; short c; char d; }; const size_t T_size = sizeof(struct T); -- t_interface.ads with Interfaces.C; package T_Interface is T_Size : constant Interfaces.C.size_t; pragma Import (C, T_Size, "T_size"); type Opaque_T is new Interfaces.C.char_array (1 .. T_Size); for Opaque_T'Alignment use 8; private pragma Linker_Options ("t.o"); end T_Interface; -- test.adb with Ada.Text_IO; use Ada.Text_IO; with T_Interface; use T_Interface; procedure Test is My_T : Opaque_T; begin Put_Line ("Size of T in bits:" & My_T'Size'Img); end Test; ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Interfacing to C without dynamic memory 2008-11-15 11:52 ` Samuel Tardieu @ 2008-11-16 21:31 ` Maciej Sobczak 0 siblings, 0 replies; 6+ messages in thread From: Maciej Sobczak @ 2008-11-16 21:31 UTC (permalink / raw) On 15 Lis, 12:52, Samuel Tardieu <s...@rfc1149.net> wrote: > Note that you can also do it at run time, even if it costs a few more > cycles to allocate the object, by taking advantage of C ability to > resolve "sizeof" into a static value at compile time. This obliviates > the cross-compilation issues. > const size_t T_size = sizeof(struct T); > T_Size : constant Interfaces.C.size_t; > pragma Import (C, T_Size, "T_size"); Neat. This possibility was not obvious to me. > type Opaque_T is new Interfaces.C.char_array (1 .. T_Size); > for Opaque_T'Alignment use 8; Of course, I can similarly extract the magic 8 constant from the C file (sizeof(long long) or such). Two more questions: 1. Any technical difference between System.Storage_Array and Interfaces.C.char_array? Considering that the target module is C, using the latter is more logical, but apart from "name affinity" is there anything that can make a difference in practice? 2. Now the array has run-time size instead of compile-time size (as you mentioned yourself). Is there any difference, especially in terms of memory management? Are such arrays guaranteed to be allocated on the stack? -- Maciej Sobczak * www.msobczak.com * www.inspirel.com Database Access Library for Ada: www.inspirel.com/soci-ada ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2008-11-16 21:31 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2008-11-14 13:58 Interfacing to C without dynamic memory Maciej Sobczak 2008-11-14 20:35 ` Damien Carbonne 2008-11-15 1:12 ` Randy Brukardt 2008-11-14 23:13 ` Robert A Duff 2008-11-15 11:52 ` Samuel Tardieu 2008-11-16 21:31 ` Maciej Sobczak
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox