From: Björn Persson on 22 Apr 2010 16:12 resander wrote: > void getproduct ( PRODUCT * pout , int * resultout ) > { > *resultout = guidb ( 0 , (int)pout ) ; > } Who is forcing you to cast pointers to int? I recommend applying a clue-by- four to that person's head. That code is broken on 64-bit GNU/Linux. Good luck porting that program to Windows if what you have shown is representative of its quality. Before you write the Ada binding you should fix the interface so that it's sane according to the C standard. -- Bj�rn Persson PGP key A88682FD
From: Keith Thompson on 22 Apr 2010 17:12 resander <kresander(a)gmail.com> writes: > I am working on software that manipulates SQL databases via a GUI. It > is written in C or C++ without classes and compiled on Linux. Would > also want it to run on Windows eventually. This software has > essentially one entry procedure: > > int guidb ( int appno , int recaddress ); // in C > > which returns an outcome as an int, takes an int appno which specifies > application and an address of a record in recaddress. The latter is > used for passing the memory address of any recordtype variable and is > cast to a byte address inside guidb. [...] As others have mentioned, this is bad C. There is no guarantee that an int can hold the value of an address, and there are common systems (including Linux systems) where it can't. Worse, you're not likely to get a warning if you convert a pointer to int, even if there's a loss of information. The right type for this parameter is void* (which is roughly analogous to Ada's System.Address). -- Keith Thompson (The_Other_Keith) kst-u(a)mib.org <http://www.ghoti.net/~kst> Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"
From: resander on 23 Apr 2010 08:58 On Apr 22, 10:12 pm, Keith Thompson <ks...(a)mib.org> wrote: > resander <kresan...(a)gmail.com> writes: > > I am working on software that manipulates SQL databases via a GUI. It > > is written in C or C++ without classes and compiled on Linux. Would > > also want it to run on Windows eventually. This software has > > essentially one entry procedure: > > > int guidb ( int appno , int recaddress ); // in C > > > which returns an outcome as an int, takes an int appno which specifies > > application and an address of a record in recaddress. The latter is > > used for passing the memory address of any recordtype variable and is > > cast to a byte address inside guidb. > > [...] > > As others have mentioned, this is bad C. > > There is no guarantee that an int can hold the value of an address, > and there are common systems (including Linux systems) where it > can't. Worse, you're not likely to get a warning if you convert > a pointer to int, even if there's a loss of information. > > The right type for this parameter is void* (which is roughly > analogous to Ada's System.Address). > > -- > Keith Thompson (The_Other_Keith) ks...(a)mib.org <http://www.ghoti.net/~kst> > Nokia > "We must do something. This is something. Therefore, we must do this." > -- Antony Jay and Jonathan Lynn, "Yes Minister" Thank you all for your concerns about using an int for passing an address. The interface actually uses a void * (could also be char * as that is what is needed), but I changed it for the post because I thought an all-int interface would be easier to handle at the Ada-to-C boundary. That seems to have backfired! It may help if I give some background info, so just briefly the program (with guidb as the main entry routine) moves record data to/ from GUI dialogs and to and from SQL databases via ODBC. A record in host language may be passed in or in-and-out. The guidb is not compiled with host language units and would exist as a dll, shared object or a static library. It uses a record memory address, record length and field offsets and field types/length in order to access a record and move the record around. This information is held in tables local to guidb. The record length and field data are passed accross via another entry point: void givefldinfo ( int recordtypeid , -- key int recordlength , int numflds , int fldoffsets[] , int typeinfo[] ); The givefldinfo is called for each record type by initialisation routines that are generated automatically from design-time or repository information. They are compiled and linked with the host application and called behind the scenes. Usually GUI events are handled internally, but may also be handled by event procedures in the host language. Host language handlers have signatures ( bool valin ),( int valin ), ( char valin[] ) and ( RECORDTP * valinout ). There are four additional entry points, one for each event handler signature to get the proc address across from host language. These are called in a manner similar to givefldinfo. I am on Linux and installed Ada GPS yesterday. Experimented a bit and found that X.fld'Position gave me the field offsets and X'Size the record size. I also tried getting the address of a record and its fields using X'Address and X.fld'Address, but they all came out negative. Prodrecord address: -1079352648 code field address: -1079352648 bcode field address: -1079352644 ccode field address: -1079352643 third field address: -1079352640 descr field address: -1079352636 price field address: -1079352624 for record code : integer; bcode : character; ccode : character; third : integer; descr : String(1..10); price : float; by: prod : PRODUCT; a: System.Address; function Conv is new Ada.Unchecked_Conversion ( Source => System.Address, Target => Integer); ... a := prod'Address; put( "Prodrecord address: " ); s := conv ( a ) ; put(s); new_line; a := prod.code'Address; put( " code field address: " ); s := conv ( a ) ; put(s); new_lin ... Q1. Addresses are not negative. How do I output a System.Address? Dmitri: Many thanks for showing how to code the generic Get routine. I have never used generics or interfaced to C before and it was so long time ago I used Ada (where is my walking stick?) so I don't understand it well enough. Q2. What is the effect of aliased in 'Data : aliased Data_Type;'? Data is a local variable. I am confused by the aliased keyword, but it would seem guidb copies the record into this and then the record value is copied once more into final location (X:Product). If so, one copy operation is redundant. Q3. The wrapper: procedure getprod (p:out PRODUCT;res:out int) is begin result = guidb ( 0 , addrin(p)??? ) ; end hides the details of calling the C function and returns data to the record variable in the calling program if the address carried by the formal parameter can be obtained inside the wrapper. Using p'Address for the second actual parameter of guidb would probably just give the address of the formal (will check when I know how to output a System.Address). Is it possible to obtain the memory address of the record variable via formal parameter p? Q4. Would it be easier to implement this if the wrapper was changed to: procedure getprod (p: in System.Address; res:out int) is begin result = guidb ( 0 , what goes here??? ) ; end with user calling it as: getprod ( recordvar'Address , result ); Q5. Host language event handler procedures are stored as an array of procedure addresses which is local to guidb. A procedure is called indirectly via this array. This was designed for C/C++, but it would be nice to use the same or similar mechanism for Ada. Is this going to be possible? I think interfacing to Ada can be done, but my knowledge about this is still very limited. Your help would be most appreciated. Regards Ken
From: Dmitry A. Kazakov on 23 Apr 2010 10:15 On Fri, 23 Apr 2010 05:58:05 -0700 (PDT), resander wrote: > It may help if I give some background info, so just briefly the > program (with guidb as the main entry routine) moves record data to/ > from GUI dialogs and to and from SQL databases via ODBC. There is GNADE ODBC, Ada bindings to ODBC. So you can drop C/C++ altogether. > for record > code : integer; bcode : character; > ccode : character; third : integer; > descr : String(1..10); price : float; > by: > prod : PRODUCT; > a: System.Address; > function Conv is new Ada.Unchecked_Conversion ( > Source => System.Address, > Target => Integer); > ... > a := prod'Address; > put( "Prodrecord address: " ); > s := conv ( a ) ; > put(s); > new_line; > > a := prod.code'Address; > put( " code field address: " ); > s := conv ( a ) ; > put(s); > new_lin > ... > Q1. > Addresses are not negative. Never use Unchecked_Conversion unless you exactly know what you are doing... Address is modular, when bit-wise converted to a *signed* integer the result is expectedly surprising. > How do I output a System.Address? The example above in legal Ada: with Ada.Text_IO; use Ada.Text_IO; with System.Storage_Elements; use System.Storage_Elements; with Interfaces.C; use Interfaces.C; procedure Test_Fields is type Product is record Code : int; -- Use only C-compatible types when you communicate Bcode : char; -- to C Ccode : char; Third : int; Descr : char_array (1..10); Price : c_float; end record; pragma Convention (C, Product); P : aliased Product; begin Put_Line ("P'Address:" & Integer_Address'Image (To_Integer (P'Address))); Put_Line ("P.Code'Address:" & Integer_Address'Image (To_Integer (P.Code'Address))); Put_Line ("P.Descr'Address:" & Integer_Address'Image (To_Integer (P.Descr'Address))); end Test_Fields; gives: P'Address: 38207168 P.Code'Address: 38207168 P.Descr'Address: 38207180 > Dmitri: > Many thanks for showing how to code the generic Get routine. I have > never used generics or interfaced to C before and it was so long time > ago I used Ada (where is my walking stick?) so I don't understand it > well enough. Ada generic is roughly what C++ calls template. > Q2. > What is the effect of aliased in 'Data : aliased Data_Type;'? > > Data is a local variable. I am confused by the aliased keyword, but it > would seem guidb copies the record into this and then the record value > is copied once more into final location (X:Product). If so, one copy > operation is redundant. "aliased" means "dear compiler, I plan to take pointers (access type) to this thing." The compiler will reject Data'Access otherwise, because without your hint it is free to allocate it in a way that Data would have no valid machine address at all. > Q3. > The wrapper: > procedure getprod (p:out PRODUCT;res:out int) is > begin > result = guidb ( 0 , addrin(p)??? ) ; > end > > hides the details of calling the C function and returns data to the > record variable in the calling program if the address carried by the > formal parameter can be obtained inside the wrapper. Using p'Address > for the second actual parameter of guidb would probably just give the > address of the formal (will check when I know how to output a > System.Address). > Is it possible to obtain the memory address of the record variable via > formal parameter p? In general case no, because see above. However if you declare PRODUCT a "limited type" it will be passed by reference. You also [worse] can procedure getprod (p: access PRODUCT; ...); BTW, your concern about copying records is absolutely ungrounded. Especially because you are using ODBC + a relational DBMS! These are so extraordinary slow, that you will note no difference even if you did hundreds of copies. > Q4. > Would it be easier to implement this if the wrapper was changed to: > > procedure getprod (p: in System.Address; res:out int) is > begin > result = guidb ( 0 , what goes here??? ) ; > end > > with user calling it as: > > getprod ( recordvar'Address , result ); The preferences are as follows: in out >> access >>>>>>>>>>> address > Q5. > Host language event handler procedures are stored as an array of > procedure addresses which is local to guidb. A procedure is called > indirectly via this array. This was designed for C/C++, but it would > be nice to use the same or similar mechanism for Ada. > Is this going to be possible? Yes, it is possible, you can have an array of access-to-procedure type. But an OO way is preferable. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: John B. Matthews on 23 Apr 2010 10:44 In article <e98bcf01-46cc-44dd-b57b-3cc7e273d9e2(a)j21g2000yqh.googlegroups.com>, resander <kresander(a)gmail.com> wrote: > Prodrecord address: -1079352648 > code field address: -1079352648 > bcode field address: -1079352644 > ccode field address: -1079352643 > third field address: -1079352640 > descr field address: -1079352636 > price field address: -1079352624 > ... > Q1. > Addresses are not negative. How do I output a System.Address? -1079352648 = 0xBFAA62B8 -1079352644 = 0xBFAA62BC .... This recent thread discusses several ways to display hexadecimal: <http://groups.google.com/group/comp.lang.ada/browse_frm/thread/f3514db0a21f9b44> A.10.8 Input-Output for Integer Types may be the most straightforward: <http://www.adaic.com/standards/05rm/html/RM-A-10-8.html> -- John B. Matthews trashgod at gmail dot com <http://sites.google.com/site/drjohnbmatthews>
|
Next
|
Last
Pages: 1 2 Prev: gnatmake problem Next: Ada.Containers Hash function for a set of small integers |