comp.lang.ada
 help / color / mirror / Atom feed
* Representing data differently
@ 2003-02-07 14:15 Daniel Allex
  2003-02-07 18:07 ` tmoran
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Daniel Allex @ 2003-02-07 14:15 UTC (permalink / raw)


In C I can represent the same data multiple ways using structs and
unions.  How and can I do this in Ada?  See example below:

//
// Example of C's representation clause
//

#include <iostream.h>

#define mt37_length 4

enum BOOL {FALSE, TRUE};

struct MT_37_header
{
    short
		:4,
		nw:6,
		mt:6;
    short
		:16;		// place holder
    short
		:16;		// place holder
    short
 		:16;		// place holder
};

struct MT_37_fields 
  {
    short
		:1,		// not used
		:1,		// spare
		surv:1,
		kill:1,
		:6,		// filler
		:6;		// filler
    short 	
		ctsl;
    short
		:1,		// not used
		:4,		// spare
		gaff:1,
		smid:5,		
		weapon_type:3,
		sif:1,
		dest:1;
    short
		ctsl_msl; 
  };

struct bool_fields
{
  short
	b0:1,b1:1,b2:1,b3:1,b4:1,b5:1,b6:1,b7:1,b8:1,
  	b9:1,b10:1,b11:1,b12:1,b13:1,b14:1,b15:1;
};

struct MT_37_bools
{
  struct bool_fields wd[mt37_length];
};

struct MT_37_words
{
  short wd0;
  short wd1;
  short wd2;
  short wd3;
};

struct MT_37_message 
{
  short msg[mt37_length];
};

union MT_37
{
  struct MT_37_header header;
  struct MT_37_message message;
  struct MT_37_fields fields;
  struct MT_37_words  words;
  struct MT_37_bools  bools;
};

typedef union MT_37 MT_37;

void main()
{
  MT_37 mt37;

  mt37.header.nw = 3;
  mt37.header.mt = 037;

  mt37.fields.surv = TRUE;
  mt37.fields.kill = TRUE;
  mt37.fields.ctsl = 022;
  mt37.fields.gaff = TRUE;
  mt37.fields.smid = 01;
  mt37.fields.weapon_type = 03;
  mt37.fields.sif = TRUE;
  mt37.fields.dest = FALSE;
  mt37.fields.ctsl_msl = 0102;

  for(int i=0; i<mt37_length; i++)
    cout<<oct<<(unsigned short)mt37.message.msg[i]<<endl;

  mt37.bools.wd[0].b15 = TRUE;  // generic boolean field 
  mt37.bools.wd[0].b13 = FALSE;  // generic boolean field 
  mt37.bools.wd[0].b12 = FALSE;  // generic boolean field 
  

  cout<<oct<<(unsigned short)mt37.words.wd0<<endl;
  cout<<oct<<(unsigned short)mt37.words.wd1<<endl;
  cout<<oct<<(unsigned short)mt37.words.wd2<<endl;
  cout<<oct<<(unsigned short)mt37.words.wd3<<endl;
  
  mt37.words.wd0 = 0;
  mt37.words.wd1 = 0;
  mt37.words.wd2 = 0;
  mt37.words.wd3 = 0;
  mt37.bools.wd[0].b15 = TRUE;  // generic boolean field 
  mt37.bools.wd[0].b11 = TRUE;  // generic boolean field 
  mt37.bools.wd[0].b7 = TRUE;  // generic boolean field 
  mt37.bools.wd[0].b3 = TRUE;  // generic boolean field 
  cout<<hex<<mt37.words.wd0<<endl;

}



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Representing data differently
  2003-02-07 14:15 Representing data differently Daniel Allex
@ 2003-02-07 18:07 ` tmoran
  2003-02-09  4:39   ` Craig Carey
  2003-02-08  0:24 ` Wojtek Narczynski
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: tmoran @ 2003-02-07 18:07 UTC (permalink / raw)


>In C I can represent the same data multiple ways using structs and
>unions.  How and can I do this in Ada?
  In Ada it's called Unchecked_Conversion.  It's "unchecked" because
there's not much the compiler can do to help check that you coded
what you meant to code.  Look it up in any Ada text.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Representing data differently
  2003-02-07 14:15 Representing data differently Daniel Allex
  2003-02-07 18:07 ` tmoran
@ 2003-02-08  0:24 ` Wojtek Narczynski
  2003-02-12 18:52 ` Martin Krischik
  2003-02-23 21:09 ` Craig Carey
  3 siblings, 0 replies; 11+ messages in thread
From: Wojtek Narczynski @ 2003-02-08  0:24 UTC (permalink / raw)


dallex@erols.com (Daniel Allex) wrote in message news:<686be06c.0302070615.3943b629@posting.google.com>...

> In C I can represent the same data multiple ways using 
> structs and unions. 

Ada doesn't have unions, because they are unsafe. For example consider
two simple types:

type Foo is Integer range 1..12;
type Bar is Integer range 20..100;

If two variables, one of each type, were using the same chunk of
memory the value of one would always be invalid.

So if there were unions in Ada the compiler could not check your
program for you.

>How and can I do this in Ada? 

Often you can use a variant record instad of a union.

There are also tricks, but of limited applicability. For example:

declare
  F : Foo := 3;
  B : Bar;
  for B'Address use F'Address;
begin
  -- Et violla! Constraint_Error
  B := B + 1;
end;

Another is to do Uncecked_Conversion between (constrained) access
types.

So this can be done, but you really need to know what you are doing.

Regards,
Wojtek



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Representing data differently
  2003-02-07 18:07 ` tmoran
@ 2003-02-09  4:39   ` Craig Carey
  2003-02-10 12:47     ` Colin Paul Gloster
  0 siblings, 1 reply; 11+ messages in thread
From: Craig Carey @ 2003-02-09  4:39 UTC (permalink / raw)



On Fri, 07 Feb 2003 18:07:34 GMT, tmoran@acm.org wrote:

>>In C I can represent the same data multiple ways using structs and
>>unions.  How and can I do this in Ada?
>
>  In Ada it's called Unchecked_Conversion.  It's "unchecked" because
>there's not much the compiler can do to help check that you coded
>what you meant to code.  Look it up in any Ada text.


This message provides a more details and it has an example showing how
to make two records be of the same size.


Suppose that there is a generic package that has to be instantiated
only once (otherwise, with GNAT, the executables get larger), but the
instantiated generic package has receive two completely different
types.

The generic package has this header:

   generic
      type Data_Type is private;	  --  Constrained only
      ...

The package passes these 3 checks:

  * The 'union' type is not a pointer to both records. In this option
    and unchecked conversion would be done on the pointers. It is
    simple to specify but leads to harder to write code and probably
    a larger executable.

  * The 'union' type is not a variant, and it is not a tagged type.
    Those two types are unconstrained.


--------------------------------------------------------------------

with Ada.Unchecked_Conversion;

package Bt is

   type Kind_Enum is (Kind_R1, Kind_R2, Kind_Zero);

      --  Help catch unitialized value bugs in Linux:
   for Kind_Enum use (Kind_R1 => 7, Kind_R2 => 8, Kind_Zero => 9);

   pragma Volatile (Kind_Enum);  --  Inlined code uses field's value

   type Hoof_Rec is null record;

   type R1_Rec is
      record
         X1       : Integer;
      end record;

   type R2_Rec is
      record
         Y1       : String (1 .. 7);
         Y2       : Boolean;
      end record;

   for Hoof_Rec'Alignment use 4;
   for R1_Rec'Alignment   use 4;
   for R2_Rec'Alignment   use 4;

   Size   : constant := 64;    --  Adjust by hand

   for Hoof_Rec'Size use Size;
   for R1_Rec'Size   use Size;
   for R2_Rec'Size   use Size;

   type Variant is
      record
         Kind     : Kind_Enum := Kind_Zero;
         K        : Hoof_Rec;
      end record;

   function From_R1 (X : R1_Rec) return Variant;

   function To_R1 is new Ada.Unchecked_Conversion (
               Source => Hoof_Rec, Target => R1_Rec);

private
   function From_R1 is new Ada.Unchecked_Conversion (
               Source => R1_Rec, Target => Hoof_Rec);
end Bt;

--------------------------------------------------------------------

with Text_IO;

package body Bt is

   function From_R1 (X : R1_Rec) return Variant is
   begin
      return (Kind => Kind_R1, K => From_R1 (X));
   end From_R1;

begin
   declare
      Z0    : Hoof_Rec;
      Z1    : R1_Rec;
      Z2    : R2_Rec;

      function Nim (Omicron : Natural) return String
            renames Natural'Image;

      function From_R1_To_R2 is new Ada.Unchecked_Conversion (
                  Source => R1_Rec, Target => R2_Rec);
   begin
         --  Prints "64 64 64 TRUE":

      Text_IO.Put_Line (Nim (Z0'Size) & Nim (Z1'Size) &
               Nim (Z2'Size) & ' ' &
               Boolean'Image (From_R1_To_R2 (Z1).Y2));

         --  In GNAT,T'Object_Size to get the size of the variables
         --   without defining variables.

      if Z0'Size /= Z1'Size or Z0'Size /= Z2'Size then
         raise Program_Error;
      end if;
   end;
end Bt;

--------------------------------------------------------------------

pragma Style_Checks ("3abcefhiklmnoprst");

with Bt;

procedure Bt_Main is
begin
   null;
end Bt_Main;

--------------------------------------------------------------------


The text

   "From_R1_To_R2 (Z1).Y2"

shows a way to use Unchecked_Conversion that permits the compiler to
not copy the entire record. That is permitted by AARM 13.9
(Unchecked Type Conversions), which says:

  12 An implementation may return the result of an unchecked
   conversion by reference, if the Source type is not a by-copy type.
   [In this case, the result of the unchecked conversion represents
   simply a different (read-only) view of the operand of the
   conversion.]

  12.a Ramification: In other words, the result object of a call on an
   instance of Unchecked_Conversion can occupy the same storage as the
   formal parameter S. 


For GNAT, adding a ".all" and having the conversion be applying to
a pointer to a record easily could reduce the chance of copying.

--

For completeness, the Unchecked_Conversion feature and its copying, can
be avoided, by using this technique:

   for X'Address use Y'Address;
   pragma Import (Y);
         --  :Stops default initialising of pointers (not in GNAT 3.14)


If X or Y is an "in out" mode record parameter then it could be copied
in or out. Making it tagged guarantees that that doesn't happen.

AARM 3.10 (Access Types) says:
 (9.g) A formal parameter of a tagged type is defined to be aliased so
   that a (tagged) parameter X may be passed to an access parameter P by
   using P => X'Access. Access parameters are most important for tagged
   types because of dispatching-on-access-parameters (see 3.9.2). By
   restricting this to formal parameters, we minimize problems
   associated with allowing components that are not declared aliased to
   be pointed-to from within the same record.

http://www.adaic.org/standards/95aarm/html/AA-3-10.html


--------------

A bug that ACT got rid of has been replaced with another bug in the same
place.

In 15 July 2001 I reported this error as a bug (in GNAT 3.13p, the native
FreeBSD version of FreeBSD):

| 5. function Nim (Omicron : Natural) return String renames Natural'Image;
|                  |
| >>> warning: "Omicron" is not referenced
         

With version 3.15p, there is still a warning (a minor problem):

| 17.       function Nim (Omicron : Natural) return String
| 18.             renames Natural'Image;
|                 |
|     >>> (style): subprogram body has no previous spec



G. A. Craig Carey

Speedy Ada Strings.
(The licence of the package changed: this software now can't be mixed with
software under a licence having the acronym "GMPL", with 2 exceptions: (1)
Ada Core Tech software is OK, it's exempted; (2) the "GMPL" text per
file, of the 3rd party, is cryptographically signed by Ada Core, etc.
R. R. Software seems to have its own GMPL -- I didn't see the acronym
expanded, and while undefined it is different enough under law):
http://www.ijs.co.nz/code/ada95_strings_pkg.zip

http://www.ijs.co.nz/ada_95.htm




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Representing data differently
  2003-02-09  4:39   ` Craig Carey
@ 2003-02-10 12:47     ` Colin Paul Gloster
  2003-02-13 17:21       ` Craig Carey
  0 siblings, 1 reply; 11+ messages in thread
From: Colin Paul Gloster @ 2003-02-10 12:47 UTC (permalink / raw)


From news:c5cb4v03pves595pdtq3euo1glgf5ne71q@4ax.com :
"[..]  
     for X'Address use Y'Address;
     pragma Import (Y);
           --  :Stops default initialising of pointers (not in GNAT 3.14)

[..]"

Why is the convention missing from this import statement?



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Representing data differently
  2003-02-07 14:15 Representing data differently Daniel Allex
  2003-02-07 18:07 ` tmoran
  2003-02-08  0:24 ` Wojtek Narczynski
@ 2003-02-12 18:52 ` Martin Krischik
  2003-02-22 19:09   ` Robert A Duff
  2003-02-23 21:09 ` Craig Carey
  3 siblings, 1 reply; 11+ messages in thread
From: Martin Krischik @ 2003-02-12 18:52 UTC (permalink / raw)


On Fri, 07 Feb 2003 06:15:18 +0000, Daniel Allex wrote:

> In C I can represent the same data multiple ways using structs and
> unions.  How and can I do this in Ada?  See example below:
> 
> //
> // Example of C's representation clause
> //
> struct MT_37_header
> {
>     short
> 		:4,
> 		nw:6,
> 		mt:6;
>     short
> 		:16;		// place holder
>     short
> 		:16;		// place holder
>     short
>  		:16;		// place holder
> };

Since it is quite dangerous you have to do a lot of typing:

-- snip
    type
        State
    is record
        uninitialized    : Boolean ;
        on               : Boolean ;
        writeLineNumber  : Boolean ;
        writePrefix      : Boolean ;
    end record;

    for
        State
    use record
        uninitialized   at 0 range 0..0;  
        on              at 0 range 1..1;    
        writeLineNumber at 0 range 2..2;   
        writePrefix     at 0 range 3..3;   
    end record;

-- snap

The first statement defines the record, the second defines the layout.
Nothing stops you from placing two record elements at the same position.

with regards

Martin

PS: If you like you can look at the rest of the (unfinished) source as well:

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/adacl/adacl/Include/AdaCL-Trace.adb

-- 
Martin Krischik
mailto://Martin@krischik.com
http://www.martin.krischik.com




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Representing data differently
  2003-02-10 12:47     ` Colin Paul Gloster
@ 2003-02-13 17:21       ` Craig Carey
  0 siblings, 0 replies; 11+ messages in thread
From: Craig Carey @ 2003-02-13 17:21 UTC (permalink / raw)


On 10 Feb 2003 12:47:23 GMT, Colin_Paul_Gloster@ACM.org (Colin Paul
Gloster) wrote:
...
>     for X'Address use Y'Address;
>     pragma Import (Y);
>           --  :Stops default initialising of pointers (not in GNAT 3.14)
...
>Why is the convention missing from this import statement?


That is quoted text, and the quote could have been corrected. Thus I
object to the use of the present tense in the question. It does not seem
to be an interesting question. The solution I showed is not very nice,
with how the "-gnatR" option to show byte offsets might be done, with
an a one or more edits and compiles until Ada union struct type is
defined properly.

The rule on no default initializations is defined with this text:

Ada Reference Manual : B.1 Interfacing Pragmas

38.  Notwithstanding what this International Standard says elsewhere,
the elaboration of a declaration denoted by the local_name of a pragma
Import does not create the entity. Such an elaboration has no other
effect than to allow the defining name to denote the external entity.

38.a.  Ramification: This implies that default initializations are
skipped. (Explicit initializations are illegal.) For example, an
imported access object is not initialized to null.

  http://www.adaic.org/standards/95aarm/html/AA-B-1.html





^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Representing data differently
  2003-02-12 18:52 ` Martin Krischik
@ 2003-02-22 19:09   ` Robert A Duff
  2003-02-23 13:06     ` Martin Krischik
  0 siblings, 1 reply; 11+ messages in thread
From: Robert A Duff @ 2003-02-22 19:09 UTC (permalink / raw)


"Martin Krischik" <Martin.Krischik@T-Online.de> writes:

>     for
>         State
>     use record
>         uninitialized   at 0 range 0..0;  
>         on              at 0 range 1..1;    
>         writeLineNumber at 0 range 2..2;   
>         writePrefix     at 0 range 3..3;   
>     end record;
> 
> -- snap
> 
> The first statement defines the record, the second defines the layout.
> Nothing stops you from placing two record elements at the same position.

Actually, 13.5.1(11) makes it illegal.

- Bob



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Representing data differently
  2003-02-22 19:09   ` Robert A Duff
@ 2003-02-23 13:06     ` Martin Krischik
  0 siblings, 0 replies; 11+ messages in thread
From: Martin Krischik @ 2003-02-23 13:06 UTC (permalink / raw)


On Sat, 22 Feb 2003 14:09:09 +0000, Robert A Duff wrote:

> "Martin Krischik" <Martin.Krischik@T-Online.de> writes:
> 
>>     for
>>         State
>>     use record
>>         uninitialized   at 0 range 0..0;  
>>         on              at 0 range 1..1;    
>>         writeLineNumber at 0 range 2..2;   
>>         writePrefix     at 0 range 3..3;   
>>     end record;
>> 
>> -- snap
>> 
>> The first statement defines the record, the second defines the layout.
>> Nothing stops you from placing two record elements at the same position.
> 
> Actually, 13.5.1(11) makes it illegal.
 
True.

--
(11)
At most one component_clause is allowed for each component of the type,
including for each discriminant (component_clauses may be given for some,
 all, or none of the components). Storage places within a component_list
shall not overlap, unless they are for components in distinct variants of
the same variant_part. 
--

So you have to combine the record layout with a variant record. Which make
the original request quite complex to implement. But then the C code wan't
easy either.

with Regards

Martin

-- 
Martin Krischik
mailto://Martin@krischik.com
http://www.ada.krischik.com




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Representing data differently
  2003-02-07 14:15 Representing data differently Daniel Allex
                   ` (2 preceding siblings ...)
  2003-02-12 18:52 ` Martin Krischik
@ 2003-02-23 21:09 ` Craig Carey
  2003-02-23 21:59   ` tmoran
  3 siblings, 1 reply; 11+ messages in thread
From: Craig Carey @ 2003-02-23 21:09 UTC (permalink / raw)


On 7 Feb 2003 06:15:18 -0800, dallex@erols.com (Daniel Allex) wrote:

>In C I can represent the same data multiple ways using structs and
>unions.  How and can I do this in Ada?  See example below:
...
>union MT_37
...
>typedef union MT_37 MT_37;
>

Ada Issue AI-00216 of 1999 considers a "Pragma Unchecked_Union".

The AI is online at:

  http://www.ada-auth.org/cgi-bin/cvsweb.cgi/AIs/AI-00216.TXT

  : Several Ada 95 compilers now support a pragma Unchecked_Union for
  : specifying that the discriminant of a variant record should not be
  : present at run-time, thereby matching a C union.

Other AIs:
(1) http://www.ada-auth.org/AI-SUMMARY.HTML and
(2) http://www.ada-auth.org/ais.html , files REST_AIS.ZIP,
    DEF1_AIS.ZIP, ACS.ZIP.




Craig Carey




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Representing data differently
  2003-02-23 21:09 ` Craig Carey
@ 2003-02-23 21:59   ` tmoran
  0 siblings, 0 replies; 11+ messages in thread
From: tmoran @ 2003-02-23 21:59 UTC (permalink / raw)


>>In C I can represent the same data multiple ways using structs and
>>unions.  How and can I do this in Ada?
  Sometimes the item that tells which part of the union to use is
actually nearby, and you can just use a straight Ada discriminated
record.  Another possibility is to use a discriminated record where
a case statement on the discriminant tells which of several pointers
to use to point to the actual C data.



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2003-02-23 21:59 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-02-07 14:15 Representing data differently Daniel Allex
2003-02-07 18:07 ` tmoran
2003-02-09  4:39   ` Craig Carey
2003-02-10 12:47     ` Colin Paul Gloster
2003-02-13 17:21       ` Craig Carey
2003-02-08  0:24 ` Wojtek Narczynski
2003-02-12 18:52 ` Martin Krischik
2003-02-22 19:09   ` Robert A Duff
2003-02-23 13:06     ` Martin Krischik
2003-02-23 21:09 ` Craig Carey
2003-02-23 21:59   ` tmoran

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox