comp.lang.ada
 help / color / mirror / Atom feed
From: mheaney@ni.net (Matthew Heaney)
Subject: Re: 'size attribute inheritance
Date: 1997/08/10
Date: 1997-08-10T00:00:00+00:00	[thread overview]
Message-ID: <mheaney-ya023680001008972210070001@news.ni.net> (raw)
In-Reply-To: 33ECF679.4B5D@lmco.com


In article <33ECF679.4B5D@lmco.com>, cpalenzuela@sprintmail.com wrote:

>Following is a simplified version of our example.  We are using Green 
>Hills Ada 95 targeted to Sun/Solaris. 
>     
>     type Integer_16 is range -(2**15) .. (2**15)-1; 
>     for Integer_16'size use 16;

As Bob pointed out, you don't need the size clause, as that is the size
already.  The "default" size is the number of bits needed to represent all
values in the range, no more, and no less.
    
>     subtype Natural_16 is Integer_16 range 0 .. Integer_16'last;
>     
>     subtype Month_Type is Natural_16 range 0..11;
>     
>     type Date_Type is
>     record
>     Year  : Natural_16;
>     Month : Month_Type;
>     end record;
>     
>     for Date_Type use
>     record
>     Year  at 0 range 0 .. 15;
>     Month at 0 range 16 .. 31;
>     end record;

I would put a size clause on the record, too, and an alignment clause:

for Data_Type'Size use 32;
for Data_Type'Alignment use 4;  -- I think that's the syntax

>     ...
>     When running this code, we get a bus alignment error.  We tracked
>it 
>     down to the fact that the compiler does NOT really allocate 16 bits 
>     for Month with subtype Month_Type.  We assumed that since
>Integer_16 
>     had been set up with 'size attribute of 16, subtype Natural_16
>would 
>     inherit that and so Month_Type would also inherit it. I might
>expect 
>     based on 13.3 (55) that Month_Type'size = 4 and then on 13.3 (43)
>that 
>     Month'size >= 4.  Perhaps the confusion is that only the attribute 
>     itself and not its specific value is what is inherited; I don't see 
>     anything in the ARM which says one way or the other.

(Sub)type Month_Type really is 4 bits, as that's all that is required to
represent all the values in the range 0 .. 11.  It is definately not 16
bits, even though it's a subtype of a subtype that does have a size of 16.

But you explicitly allocated 16 bits for the Month component of the
Date_Type record, so that's what you got for that component.  But read on.

Given that you're using representation clauses on a type, I assume your
reason for doing so is because you're going to read or write an object of
this type across an external interface.  As Bob also pointed out,

YOU SHOULD NEVER USE CONSTRAINED SUBTYPES TO TRANSMIT OR RECIEVE DATA
ACROSS AN EXTERNAL INTERFACE.

I'll say this another way:

USE ONLY FIRST NAMED SUBTYPES WHOSE RANGE EXACTLY MATCHES THE RANGE
REPRESENTABLE BY ITS SIZE, WHEN PERFORMING EXTERNAL I/O.

Some more advice

USE THE TYPES IN PACKAGE INTERFACES TO PERFORM EXTERNAL I/O.

I'm not trying to scream at anyone or be rude or anything, but this issue
is so important that I have to get your attention, because most Ada
programmers don't completely understand it.

The correct way to declare your date type is as follows:

type Date_Type is
   record
      Year   : Interfaces.Integer_16;
      Month : Interfaces.Integer_16;
   end record;

for Date_Type use
   record
      Year at 0 range 0 .. 15; 
      Month at 0 range 16 .. 31;
   end record;

for Date_Type'Size use 32;

for Date_Type'Alignment use 4;

When declaring actual objects of the type, for use when executing the I/O
statement, then specify a size for the object:

declare
   The_Date : Date_Type;
   for The_Date'Size use 32;
begin
   read (The_Date'Address, nbytes => 4);
end;

I'm not sure, but it might help too to declare the object as aliased and
volatile:

declare
   The_Date : aliased Date_Type;
   for The_Date'Size use 32;
   pragma Volatile (The_Date);
begin
   read (The_Date'Address, nbytes => 4);
end;


>     Putting a 'size attribute on the subtype resulted in a syntax error 
>     [assumedly based on 13.3 (48)].  It's not necessarily so bad that 
>     Month_type'size and Month'size are different from Integer_16'size,
>but 
>     I would at least expect the values of Month to be right-justified
>in 
>     the record-component field if Month'size < Integer_16'size (as
>here), 
>     but instead it is left-justified!  Is there a justification in the
>ARM 
>     for this or is this a compiler issue?   

You can only specify a size clause in the declaration of the first subtype
(the declaration "type T is...").

I'm not sure what you meant by values being "left justified" or "right
justified."

Make sure you're not having any problems with endianness, either.  On a
big-endian machine, your declaration is layed out as

                     0    15  16      31
   The_Date : year     month

on a little endian machine:

   31    16  15      0
     month    year   :  The_Date

If the value for month is at at wrong end of the month component, perhaps
that's becuase you and the device have a different endianness?  (The UNIX
guys call this "getting NUXIed.")


>We worked around this
>problem 
>     by setting up Month_Type as a type, rather than a subtype, and 
>     assigning it a 'size of 16, but the issue still has me perplexed. 
>I 
>     would appreciate any informed opinions as to what I can or should 
>     expect about the inheritance of the 'size attribute. 

Technically, you meant to say "setting up Month_Type as a first named subtype."

And no, size is not "inherited."  The size is always only what is required
to exactly represent all values of the subtype.  For example,

   type Byte is range 0 .. 255;
   for Byte'Size use 8;

   subtype Nibble is Byte range 0 .. 15;

Byte'Size is 8, and Nibble'Size is 4.

Which is the reason you should always specify a size for objects (not just
the type) used for external I/O (ie whenever you say "O'Address", you
should already have said "for O'Size use ...").

This makes sense, if you consider this

declare
   O : Nibble;
begin

A compiler can only allocate an integral number of "storage elements" for
O.  On a machine with byte addressing, O would "probably" have a size of 8,
although it could have 16 or 32.  There's no way object O could have a size
of 4, in spite of the fact that Nibble has a size of 4.  You the programmer
must specify explictly what the size of the object needs to be,
irrespective of whether the type has a size clause.

As I said (loudly, but not to be rude), never ever do I/O using other than
a first named subtype whose range exactly matches the values representable
in its size.  Types with this very characteristic are already defined for
you in package Interfaces.

If you did use a subtype with a range constraint to do external I/O, and
you got garbage over the interface, now your program is erroneous (or maybe
it's a "bounded error" now - check the AARM).  For example,  if I had a
Date_Type object, and the device put the value 16#0000_00FF# at that
address, then Date.Month has the value 255, even though it is constrained
to only have the values 0 .. 11.  If you ever try to deference that
component, then all bets are off as to the program's behavior.  (Think of
the disaster that could happen if Month were in a case statement, or used
to index an array.)

Many, many new and experienced Ada programmers naively think that
Constraint_Error will get raised.  This is completely and totally
incorrect.  Program behavior is UNDEFINED.

Perhaps your "bus alignment" error is really the result of erroneous
execution, because you have garbage in the month component of date.

You the programmer must manually check the object to make sure its value is
in the correct range.  So here's what you can do for the date:

subtype Month_Type is Natural range 0 .. 11;

declare
   The_Date : Date_Type; -- the declaration I wrote above
   for The_Date'Size use 32;
begin
   read (The_Date'Address, nbytes => 4);

   if The_Date.Month not in 0 .. 11 then
      <handle garbage value for month>
   end if;

...
end;


Another possibility is that there was already garbage in the object when
declared (because it wasn't given a default value), and the device wrote
fewer bytes than the number of bytes in the object.  For example
 
declare
   Month : Month_Type;  -- 16 bit object
begin
  <read 1 byte into Month>
end;

Now if there were garbage in the most significant byte of Month, Month
would be outside its correct range, even though the device returned a
correct value.

Here's yet another reason to not use constrained subtypes.  If I tried to
check to make sure the object had a value in the correct range:

if Month not in Month_Type'Range then
   <handle error>
end if;

the compiler might optimize the check away, under the assumption that since
Month is of subtype Month_Type, it can't be outside that subtype's range,
and therefore we can just get rid of this unnecessary check.  (There's a
T'Value attribute too, but I'm still not sure a use of it won't get
optimized away.)  Which is why I always read into unconstrained subtypes,
and do the constraint checking manually.

Hope that helps,
Matt

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




  reply	other threads:[~1997-08-10  0:00 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1997-08-09  0:00 'size attribute inheritance Carlos Palenzuela
1997-08-10  0:00 ` Matthew Heaney [this message]
1997-08-11  0:00   ` Robert Dewar
1997-08-12  0:00     ` Matthew Heaney
1997-08-13  0:00       ` Ken Garlington
1997-08-13  0:00         ` Matthew Heaney
1997-08-13  0:00       ` Robert A Duff
1997-08-13  0:00         ` Matthew Heaney
1997-08-14  0:00           ` Robert A Duff
1997-08-14  0:00             ` Dale Stanbrough
1997-08-16  0:00           ` Robert Dewar
1997-08-16  0:00             ` Ken Garlington
1997-08-17  0:00               ` Robert Dewar
1997-08-18  0:00                 ` Robert A Duff
     [not found]                   ` <dewar.872433846@merv>
1997-09-03  0:00                     ` Robert A Duff
1997-09-06  0:00                       ` Robert Dewar
1997-09-08  0:00                         ` Robert A Duff
1997-08-17  0:00               ` Robert A Duff
1997-08-10  0:00 ` Robert A Duff
1997-08-10  0:00 ` Robert Dewar
1997-08-11  0:00   ` Matthew Heaney
1997-08-11  0:00   ` Ken Garlington
replies disabled

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