On Jan 21, 1:42 pm, "Johannes Schaub (litb)" <schaub-johan...@web.de>
wrote:
> Posting my SO question to usenet:
> Hello all. I had a discussion with someone on IRC and this
> question turned up. We are allowed by the Standard to change
> an object of type `int` by a `char` lvalue.
> int a;
> char *b = (char*) &a;
> *b = 0;
Up to a point. Formally, you have undefined behavior is you try
to access the value of a after this. Practically, the value of
a will depend on the architecture: setting a to 42, then doing
the modification above, will give different results on a Sparc
than on a PC.
> Would we be allowed to do this in the opposite direction, if
> we know that the alignment is fine?
Formally, no. Practically, if the alignment and the size are
sufficent, you should get the same results as a memcpy.
> The issue I'm seeing is that the aliasing rule does not cover the simple
> case of the following, if one considers the aliasing rule as a non-symmetric
> relation
> int a;
> a = 0;
I'm not sure I understand.
> The reason is, that each object contains a sequence of `sizeof(obj)`
> `unsigned char` objects (called the "object representation").
I'm not sure that "contains" is the right word. Each complete
object lives in a sequence of sizeof(obj) bytes of raw memory.
> If we change the `int`, we will change some or all of those
> objects. However, the aliasing rule only states we are allowed
> to change a `int` by an `char` or `unsigned char`, but not the
> other way around. Another example
The standard doesn't quite say that. It says that access to the
stored value of an object must be through an lvalue of the
object type, or through an lvalue of a char or unsigned char
type (plus a few other cases which don't concern us here).
> int a[1];
> int *ra = a;
> *ra = 0;
> Only one direction is described by 3.10/15 ("An aggregate or union type that
> includes..."), but this time we need the other way around ("A type that is
> the element or non-static data member type of an aggregate...").
> Is the other direction implied?
Certainly not. On some rare machines, int's may have trap
values, and the values in the bytes in an array of unsigned char
may correspond to one of those values. Replace int by float,
and most of the machines I know do have trap values.
There is one important exception: if you memcpy bytes out of
some type, you can memcpy those bytes back into an object of
that type, and you're guaranteed to get the same value, i.e.:
float in = 3.14159;
float out;
unsigned char buf[sizeof(float)];
memcpy(buf, &in, sizeof(float));
memcpy(&out, buf, sizeof(float));
std::cout << out << std::endl;
is guaranteed to output 3.14159, but
float out;
unsigned char buf[sizeof(float)];
random_fill(buf, buf + sizeof(float));
memcpy(&out, buf, sizeof(float));
std::cout << out << std::endl;
is undefined behavior, and might even crash.
--
James Kanze
|