On Sun, Jan 10, 2010 at 06:24:14PM +0000, Dave Korn wrote:
> Eric Botcazou wrote:
> >> The aliasing rules treat "char" specially because char is a bit like a
> >> "poor main's void".
> > 
> > Not symmetrically though, only for the type of the lvalue expression used 
> > to 
> > access the object (C99 6.5.7).
> > 
> 
>   Ok.  So if I had four ints, and I wanted to cast the pointers to char and
> compare them as 16 chars, that would be OK, because the chars would alias the
> ints; but in this case, where they started as chars and I cast them to ints,
> those ints don't alias against the original chars.  Is that an accurate 
> precis?
> 
>   Andreas, you wrote: "Aliasing is not symmetric".  To be precise, we're
> saying it's not commutative here; that (A aliases B) does not imply (B aliases
> A)?  I don't think I've ever heard it expressed that explicitly before.

I think you (and several other people) are actually conflating two
separate concepts here.  One is aliasing, which can be described as "when
can two different lvalues actually refer to the same object".
The other is if it is actually allowed to access a particular object
through a given lvalue.
These two concepts partially overlap, but they are not the same.
I would say that aliasing actually is symmetric such that if (A aliases
B) then (B aliases A), but that does not necessarily mean that it is
safe to access the underlying object through both A and B.
(This just depends on how one defines the term "aliasing". Note that
aliasing is only defined indirectly in the C standard, and the term
itself only occurs in non-normative text.)

Take for example the following situation:

 float f=0;
 int main(void)
        {
        char *cp = (char *)&f;
        float *fp = &f;

        *cp = 42;

        *fp;

        return 0;
        }

Here the lvalues '*cp' and '*fp' clearly alias each other, in that they
both refer to the object 'f'.  Section 6.5p7 does not disallow access
to 'f' either through '*fp' (which has the same type as the effective
type of the object, i.e. 'float') or through '*cp' (whose type is a
character type.)  (Also note that 6.5p7 is irrelevant when storing a
value into '*cp' since that section only talks about accessing the
stored value of an object, i.e. reading from it.)

However the access to 'f' through the lvalue '*fp' still invokes
undefined behaviour since it may at that point contain a trap
representation.
(If the order of the expressions '*cp = 42' and '*fp' had been
switched around, then no undefined behaviour would have occurred.)



The standard has special language at several places that essentially
says that you can treat any object as an array of unsigned chars both
when reading and writing to the object. (You can mostly treat any
object as an array of char, or array of signed char as well, but since
a signed char can have a trap representation it is not necessarily safe
to read from such an lvalue in all situations.  Unsigned char is the
only type guaranteed to not have any trap representation.)
There is no such special language for any other types.

If one ignores the special case of character types, the rules basically
boil down to:

 If an object has been declared with some specific type (this includes
 all objects with automatic or static storage duration) then you can
 only read from it using an lvalue whose type is compatible with the
 type as the object.  (Possibly with differences in signed/unsigned
 specification and in qualifiers as described in 6.5p7)

 If an object does not have a declared type (such as memory allocated
 through malloc) then if you have stored a value there using an lvalue
 of some specific type, then you can only read the value using an lvalue
 of compatible type. (Again possibly with differences in qualifiers and
 signed/unsigned specifiers.)

(Assuming the object is suitably aligned and large enough, there is not
really any prohibition against storing a value into an object using an
lvalue of a completely different type, but since you cannot read that
value back there is not much point in doing so.)

Note that most sorts of "type punning" (i.e. treating an object as if
it was of a different type than it actually is) is disallowed by the C
standard.

In particular accessing an array of chars as if it was an array of int is
not allowed any more than accessing an array of int as if it was an
array of float.





-- 
<Insert your favourite quote here.>
Erik Trulsson
ertr1...@student.uu.se

Reply via email to