From: resander on
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.

guidb uses appno to locate field-offsets and length of the recordtype
in tables built by initialisation functions for all recordtypes that
take part.

Typical use in C/C++:

typedef struct { int prodcode; float price; char descr [50]... }
PRODUCT;
typedef struct { bool bitesyou; int speciescode; char name[20] ... }
ANIMAL ;

void getproduct ( PRODUCT * pout , int * resultout )
{
*resultout = guidb ( 0 , (int)pout ) ;
}

void addtozoo ( ANIMAL * a , int * resultout )
{
*resultout = guidb ( 1 , (int)a ) ;
}

PRODUCT prod ;
ANIMAL addthis ;
int outcome ;

// use as...

getproduct ( &prod , &outcome );
// get addthis animal data then
addtozoo ( &addthis , &outcome );

All wrappers like getproduct and addtozoo are automatically generated
from other specs. That is easy in C by using fldoffset macro to get
field offsets and sizeof(rectypename) to get record length and a cast
that changes the interpretation of address to an int.

Desired use in Ada (same as above):

type PRODUCT is RECORD int prodcode; float price; char descr
[50]...END RECORD;

procedure getproduct ( p : out PRODUCT ; result : out int ) is
begin
result = guidb ( 0 , address_of(p) how ??? ) ;
end

prod : PRODUCT;
outcome : int ;

getproduct ( prod , outcome );


To be able to use the guidb with Ada I need to know how to:

- get the memory address carried (how?) by the record formal
parameter
- obtain field offsets for a record type
- obtain length of a record object/variable

How to do this in in Ada? If it cannot be done, can the interface
above be changed to make it possible?

Ken

From: Dmitry A. Kazakov on
On Wed, 21 Apr 2010 09:43:02 -0700 (PDT), resander wrote:

> 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

This is awful even on C standards.

> 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.

[...]

> Desired use in Ada (same as above):
>
> type PRODUCT is RECORD int prodcode; float price; char descr
> [50]...END RECORD;
>
> procedure getproduct ( p : out PRODUCT ; result : out int ) is
> begin
> result = guidb ( 0 , address_of(p) how ??? ) ;
> end
>
> prod : PRODUCT;
> outcome : int ;

[...]

> How to do this in in Ada? If it cannot be done, can the interface
> above be changed to make it possible?

Make it a generic function:

SQL_Error : exception;

generic
type Data_Type is private;
function Generic_Get (No : Integer) return Data_Type;

The implementation of:

with Ada.Exceptions; use Ada.Exceptions;
with Interfaces.C; use Interfaces.C;

function Generic_Get (No : Integer) return Data_Type is
function Internal (No : int; Data : access Data_Type) return int;
pragma Import (C, Internal, "guilib");
Data : aliased Data_Type;
Result : int;
begin
Result := Internal (int (No), Data'Access);
if Result /= 0 then
Raise_Exception
(SQL_Error'Identity, "Error code:" & int'Image (Result));
else
return Data;
end if;
end Generic_Get;

Declare a type you need, e.g. Product:

type Product is record
Code : int;
Price : float;
Descr : char_array (1..50);
end record;
pragma Convention (C, Product); -- Note this pragma!

Instantiate the function:

function Get is new Generic_Get (Product);

Use it as:

X : Product := Get (0);

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
From: Robert A Duff on
resander <kresander(a)gmail.com> writes:

> On Apr 22, 10:12�pm, Keith Thompson <ks...(a)mib.org> wrote:
>> 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.

Why? I'd think if int is smaller than whatever*, then
a cast to int clearly deserves a warning.

>> The right type for this parameter is void* (which is roughly
>> analogous to Ada's System.Address).

Yeah, roughly. System.Address is somewhat lower level than
C's void*.

> 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!

You should look at section B (especially B.3) of the Ada RM.
There's a type char_star you can use.

There's no void_star. I'm not sure why -- probably this
part of Ada predates void* in C, and nobody bothered
to upgrade Ada to match the new C.

> Q1.
> Addresses are not negative. How do I output a System.Address?

In GNAT, there is a function System.Address_Image.
Look at the file s-addima.ads in your GNAT
distribution.

Beware: this is not portable to other Ada compilers.

- Bob
From: Maciej Sobczak on
On 26 Kwi, 21:57, Keith Thompson <ks...(a)mib.org> wrote:

> But C still requires char* and void* to have the same representation.
>
> But in the Ada RM, I only see char_star in an example:
>
>     subtype Char_Star is Char_Ptrs.Pointer;

I use this:

subtype Void_Ptr is System.Address;

It works like a charm. Please note that in order to link Ada with C
there is a need for a *pair* of *compatible* compilers - you cannot
compile the Ada part with a random Ada compiler and a C part with a
random C compiler and expect them to work together. There is a lot of
hand-waving in the multilanguage development, which means lots of
under-the-table assumptions can be taken for granted even though they
are not explicitly covered by any of the language standards.

--
Maciej Sobczak * http://www.inspirel.com

YAMI4 - Messaging Solution for Distributed Systems
http://www.inspirel.com/yami4
From: Randy Brukardt on
"Robert A Duff" <bobduff(a)shell01.TheWorld.com> wrote in message
news:wcceii1g308.fsf(a)shell01.TheWorld.com...
> Keith Thompson <kst-u(a)mib.org> writes:
....
>> The document I'm looking at is "Ada Reference Manual, ISO/IEC
>> 8652:2007(E) Ed. 3", "ISO/IEC 8652:1995(E) with Technical Corrigendum 1
>> and Amendment 1". Is that the most current version?
>
> No. The most current standard is here:
>
> http://www.ada-auth.org/

Actually, the title Keith gives is that of the most recent "official"
consolidated edition. And the on-line versions of the Ada 2005 stuff are
found in
http://www.adaic.org/standards/ada05.html
(You can get the source and tools for generating the standard from
www.ada-auth.org, but that is something that very few people need.)

> after you rummage aroung a bit. Look for the Ada 2005 version. The
> most current future to-be-standardized version (for Ada 2012) is here:
>
> http://www.adaic.org/standards/ada1z.html
>
> Note that this one has no official ISO status yet.

Note that the above URL is going to change drastically when the next draft
version is posted (probably next week). It is going to move to
www.ada-auth.org and will be named Ada 2012 (instead of the "1z"). I'll try
to maintain some sort of forwarding, but it is best to change you bookmarks
then.

So to sum up, Bob got it exactly backwards. ;-)

....
>> There's no need for nul, wide_nul, and char32_nul to be
>> implementation-defined; they're all zero by definition:
>>
>> nul : constant char := char'val(0);
>> ...
>> wide_nul : constant wchar_t := wchar_t'val(0);
>> ...
>> char32_nul : constant char32_t := char32_t'val(0);
>
> Yes, I think that makes sense. See also AI95-00037.
>
>> C doesn't actually have a type corresponding to char32_t; it has
>> wchar_t, but its size is implementation-defined.

I believe that the char16 and char32 types were to match some proposed C
update; not sure if that was ever adopted. Ah, here's what AI95-00285-1 has
to say on the subject:

-- SC22/WG14 is planning to include support for Unicode 16- and 32-bit
characters
-- in C. Their proposal is presented in ISO/IEC TR 19769:2004
-- (http://www.open-std.org/jtc1/sc22//WG14/www/docs/n1040.pdf). In order to
-- provide compatibility with the upcoming C standard, new types are added
to
-- Interfaces.C that correspond to C char16_t and char32_t. It is recognized
that
-- adding new declarations to predefined units can cause incompatibilities,
but it
-- is thought that the new identifiers are unlikely to conflict with
existing
-- code.

We may have jumped the gun on adding these, but as Bob noted, we're not
going to remove them as the incompatibility would be significant and it's
harmless to have them.

Randy.