C++ aliasing rules

mike stump mrs@windriver.com
Tue Apr 23 19:35:00 GMT 2002


> To: Dan Nicolaescu <dann@godzilla.ICS.UCI.EDU>
> Cc: libstdc++@gcc.gnu.org, gcc@gcc.gnu.org
> From: Jason Merrill <jason@redhat.com>
> Date: Tue, 23 Apr 2002 10:43:27 +0100

> > struct first  {  int i; char a;  int f1;  char f2; double d;};
> > struct second {  char b;  int f2;  int f3;};

> > can it be assumed that given that "first" and "second" are
> > incompatible then ps1.f1 and ps2.f2 don't alias

This would be an excellent question for comp.std.c.  C++ mostly just
followed C on this.  We fixed a few things (made memcpy so that it can
be portably written within the rules of the language), but it should
mostly be the same.  You would need complete code, and might need to
`fix up' the example so that you can have them answer the question you
wanted.

Consider:

struct { char buf[sizeof (double)]; short i; } secondo, *second = &secondo;
struct { double other; short i; } firsto, *not_really_first = &secondo;

and the question of whether or not first->i can ever alias second->i.

I suspect the closest we can come would be to

  memcpy (&secondo, &firsto, sizeof (secondo));

and then play with not_really_first->i and second->i.

I think the answer is no, as no matter what you do, you need to
violate the notion of which struct type the object really was and you
cannot get at the short without going though the struct first, and in
the end, you cannot get through both struct types simultaneously.

No, before you implement this, you need to be aware that some
prefixing is probably ok:

       6.3.2.3  Structure and union members

       Constraints

       [#1] The first operand  of  the  .  operator  shall  have  a
       qualified  or  unqualified  structure or union type, and the
       second operand shall name a member of that type.

       [#2] The first operand of the -> operator  shall  have  type
       ``pointer   to   qualified  or  unqualified  structure''  or
       ``pointer to  qualified  or  unqualified  union,''  and  the
       second operand shall name a member of the type pointed to.

       Semantics

       [#3] A postfix expression followed by the . operator and  an
       identifier  designates  a  member  of  a  structure or union
       object.  The value is that of the named member,  and  is  an
       lvalue  if  the first expression is an lvalue.  If the first
       expression has  qualified  type,  the  result  has  the  so-
       qualified version of the type of the designated member.

       [#4] A postfix expression followed by the -> operator and an
       identifier  designates  a  member  of  a  structure or union
       object.  The value is that of the named member of the object
       to which the first expression points, and is  an  lvalue.66
       If  the  first  expression is a pointer to a qualified type,
       the result has the so-qualified version of the type  of  the
       designated member.

       [#5] With one exception, if the value of a member of a union
       object  is used when the most recent store to the object was
       to a  different  member,  the  behavior  is  implementation-
       defined.67  One  special  guarantee  is  made  in  order  to


       __________

       66. If  &E  is  a  valid  pointer expression (where & is the
           ``address-of'' operator, which generates  a  pointer  to
           its  operand),  the  expression (&E)->MOS is the same as
           E.MOS.

       67. The  ``byte  orders''  for scalar types are invisible to
           isolated programs that do not indulge  in  type  punning
           (for  example, by assigning to one member of a union and
           inspecting the storage by accessing another member  that


       Language                                                  85









       Working Draft, 1997-11-21, WG14/<a href="n794.htm">N794</a> J11/97-158


       simplify the use of unions:  If  a  union  contains  several
       structures that share a common initial sequence (see below),
       and if the union object  currently  contains  one  of  these
       structures,  it  is  permitted to inspect the common initial
       part of any of them  anywhere  that  a  declaration  of  the
       completed  type  of  the  union  is visible.  Two structures
       share a common initial  sequence  if  corresponding  members
       have compatible types (and, for bit-fields, the same widths)
       for a sequence of one or more initial members.

       Examples

       [#6]

         1.  If f is a function returning a structure or union, and
             x  is  a member of that structure or union, f().x is a
             valid postfix expression but is not an lvalue.

         2.  The following is a valid fragment:

                     union {
                             struct {
                                     int     alltypes;
                             } n;
                             struct {
                                     int     type;
                                     int     intnode;
                             } ni;
                             struct {
                                     int     type;
                                     double  doublenode;
                             } nf;
                     } u;
                     u.nf.type = 1;
                     u.nf.doublenode = 3.14;
                     /* ... */
                     if (u.n.alltypes == 1)
                             if (sin(u.nf.doublenode) == 0.0)
                                     /* ... */






       ____________________________________________________________

           is  an appropriately sized array of character type), but
           must be accounted  for  when  conforming  to  externally
           imposed storage layouts.



       86                                                  Language









                    Working Draft, 1997-11-21, WG14/<a href="n794.htm">N794</a> J11/97-158


         3.  The following is not a  valid  fragment  (because  the
             union type is not visible within function f):

                     struct t1 { int m; };
                     struct t2 { int m; };
                     int f(struct t1 * p1, struct t2 * p2)
                     {
                             if (p1->m < 0)
                                     p2->m = -p2->m;
                             return p1->m;
                     }
                     int g()
                     {
                             union {
                                     struct t1 s1;
                                     struct t2 s2;
                             } u;
                             /* ... */
                             return f(&u.s1, &u.s2);
                     }

       Forward  references:   address  and  indirection   operators
       (6.3.3.2), structure and union specifiers (6.5.2.1).

And from the C++ world:

  - a type that is a (possibly cv-qualified)  base  class  type  of  the
    dynamic type of the object,

and:

14Two POD-struct (9) types are layout-compatible if they have  the  same
  number  of  members, and corresponding members (in order) have layout-
  compatible types (3.9).

15Two POD-union (9) types are layout-compatible if they  have  the  same
  number  of  members,  and  corresponding  members  (in any order) have
  layout-compatible types (3.9).

  +-------                     BEGIN BOX 2                      -------+
  Shouldn't this be the same set of types?
  +-------                      END BOX 2                       -------+


16If a POD-union contains two or more POD-structs that  share  a  common
  initial  sequence,  and if the POD-union object currently contains one
  of these POD-structs, it is permitted to inspect  the  common  initial
  part  of any of them.  Two POD-structs share a common initial sequence
  if corresponding members have layout-compatible types (and,  for  bit-
  fields,  the  same  widths)  for  a  sequence  of  one or more initial
  members.

17A pointer to a POD-struct object, suitably converted,  points  to  its
  initial  member (or if that member is a bit-field, then to the unit in
  which it resides) and vice versa.  [Note:  There  might  therefore  be
  unnamed  padding within a POD-struct object, but not at its beginning,
  as necessary to achieve appropriate alignment.  ]



More information about the Libstdc++ mailing list