By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,137 Members | 1,024 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,137 IT Pros & Developers. It's quick & easy.

Unions Redux

P: n/a
Ok, we've had two long and haphazard threads about unions recently,
and I still don't feel any closer to certainty about what is permitted
and what isn't. The other thread topics were "Real Life Unions"
and "union {unsigned char u[10]; ...} ".

Here's a concrete example:

#include <stdio.h>

int main(void)
{
union { int s; unsigned int us; } u;

u.us = 50;
printf("%d\n", u.s);
return 0;
}

Is this program well-defined (printing 50), implementation-defined, or
UB ?

Note that the aliasing rules in C99 6.5 are not violated here -- it is
not forbidden under that section to access an object of some type T
with an lvalue expression whose type is the signed or unsigned
version of T.

In other words, is there anything other than the aliasing rules that
restrict 'free' use of unions?

Mar 14 '07 #1
Share this Question
Share on Google+
26 Replies


P: n/a
Old Wolf <ol*****@inspire.net.nzwrote:
[ snip ]
union { int s; unsigned int us; } u;
u.us = 50;
printf("%d\n", u.s);
I was looking at N1124. Annex J lists among the unspecified
behaviors,

-- The value of a union member other than the last one stored
into (6.2.6.1).

Annex J is informative, not normative, but it still makes sense to
look at section 6.2.6.1 to see why the behavior is unspecified.
There we see that u.s and u.us have object representations as
sequences of unsigned char (paragraphs 2,4), but that some object
representations may be trap representations leading to undefined
behavior when you access u.s (par. 5). Further down, 6.2.6.2(1-2)
leave open the possibility that int has more trap representations
than unsigned int, for example if there are padding bits or if ints
are sign-magnitude and M<N-1 in 6.2.6.2(2).

So it seems that your code has undefined (not just unspecified)
behavior, by 6.2.6.1(5).

If you want to read your 50 as a signed int, you need to convert
the bits, e.g. by assignment, u.s= u.us; on a really wicked machine,
that assignment need not be a no-op !

My argument doesn't work the other way. 6.2.6.2(5) says:

A valid (non-trap) object representation of a signed integer
type where the sign bit is zero is a valid object representation
of the corresponding unsigned type, and shall represent
the same value.

so I haven't ruled out
u.s = 50;
printf("%u\n", u.us);

I can't see anything else in 6.2.6.1 that could rule it out, either.
Paragraph 6.2.6.1(7) applies, but I'm pretty sure that sizeof(int)==
sizeof(unsigned int) by 6.2.6.2 so there are no leftover bytes
for (7) to ... bite (D'oh).

Note that the aliasing rules in C99 6.5 are not violated here -- it is
not forbidden under that section to access an object of some type T
with an lvalue expression whose type is the signed or unsigned
version of T.
I don't think that's relevant. It says that the compiler must
assume, for optimization purposes, that u.s and u.us are potentially
aliased (well, duh). For example,

memcpy(buf, &u.us, sizeof(u.us)); /* unsigned char buf[BIG] */
do_something((const unsigned char *)buf);
u.s= 50;
memcpy(buf, &u.us, sizeof(u.us)); /* can't optimize out */

In other words, is there anything other than the aliasing rules that
restrict 'free' use of unions?
As I said, I don't think the aliasing rules matter. Your example
amounts to a C++ reinterpret_cast<intand can hit a trap
representation.
--
pa at panix dot com
Mar 15 '07 #2

P: n/a
On 14 Mar 2007 15:10:44 -0700, "Old Wolf" <ol*****@inspire.net.nz>
wrote in comp.lang.c:
Ok, we've had two long and haphazard threads about unions recently,
and I still don't feel any closer to certainty about what is permitted
and what isn't. The other thread topics were "Real Life Unions"
and "union {unsigned char u[10]; ...} ".
Most of the rambling was caused by the original OP, I think, rather
than the material. I am not criticizing, just observing.
Here's a concrete example:

#include <stdio.h>

int main(void)
{
union { int s; unsigned int us; } u;

u.us = 50;
printf("%d\n", u.s);
return 0;
}

Is this program well-defined (printing 50), implementation-defined, or
UB ?
The program is well-defined, I'll elaborate further down.
Note that the aliasing rules in C99 6.5 are not violated here -- it is
not forbidden under that section to access an object of some type T
with an lvalue expression whose type is the signed or unsigned
version of T.
As you pointed out, it does not violate the alias rules, but there are
other rules to consider. In this particular case, you are accessing
an object of type unsigned int with an lvalue expression of type
signed int. The entire question of the validity of the operation
depends on the object representation compatibility, and has nothing at
all to do with the fact that there is a union involved.

In this particular case, the operation is well-defined because of the
standard's guarantees about corresponding signed and unsigned integer
types. For a positive value within the range of both types, the bit
representation is identical for both.

However, if you had assigned INT_MAX + 1 to u.us, and your
implementation is one of the universal ones where UINT_MAX INT_MAX,
the behavior would be implementation-defined because, at least
theoretically, (unsigned)INT_MAX + 1 could contain a bit pattern that
is a trap representation for signed int.
In other words, is there anything other than the aliasing rules that
restrict 'free' use of unions?
Personally, I think people get to wound up in the mystical and magical
properties of unions.

They are good for two things:

1. Space saving, such as a struct containing a data type specifier
and a union of all the possible data types. This is a frequent
feature in message passing systems. Generally, type punning is not
used here.

2. Another way to do type punning.

Consider:

int test_lone(long l)
{
int *ip = (int *)&l;
int i = *ip;
return i==l;
}

Is this code undefined, implementation-defined, or unspecified?

Technically it is undefined, but on an implementation like today's
typical desktop, where int and long have the same representation and
alignment, the result will be that the function returns 1. On an
implementation where int and long are different sizes, who knows.

Now consider:

int test_long(long l)
{
union { long ll; int ii } li;
li.ll = l;
return li.ll==li.ii;
}

Is this code undefined? Well, yes, but it is no different in
functionality than the first function. If int and long have the same
representation, it will return 1.

There is no difference in aliasing in a union than there is via
pointer casting.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Mar 15 '07 #3

P: n/a
On Mar 14, 6:10 pm, "Old Wolf" <oldw...@inspire.net.nzwrote:
Ok, we've had two long and haphazard threads about unions recently,
and I still don't feel any closer to certainty about what is permitted
and what isn't. The other thread topics were "Real Life Unions"
and "union {unsigned char u[10]; ...} ".

Here's a concrete example:

#include <stdio.h>

int main(void)
{
union { int s; unsigned int us; } u;

u.us = 50;
printf("%d\n", u.s);
return 0;
}

Is this program well-defined (printing 50), implementation-defined, or
UB ?

Note that the aliasing rules in C99 6.5 are not violated here -- it is
not forbidden under that section to access an object of some type T
with an lvalue expression whose type is the signed or unsigned
version of T.

In other words, is there anything other than the aliasing rules that
restrict 'free' use of unions?
C89: undefined.
It is undefined because the member of the union accessed is not the
member last stored, this is explicitly stated in the Standard.

C99: well-defined.
In C99 the aliasing rules and representation requirements determine
the legitimacy in this case. As you noted, your example does not
violate the aliasing rules so you are good there. The Standard
explicitly states that the set of non-negative values common to any
given signed integer type and its corresponding unsigned type have the
same representations in both types so you are good there as well.

Robert Gamble

Mar 15 '07 #4

P: n/a
On Mar 15, 4:05 pm, Jack Klein <jackkl...@spamcop.netwrote:
There is no difference in aliasing in a union than there is via
pointer casting.
Thanks for finally putting the issue to rest! I'm glad it
really is that simple.

Mar 15 '07 #5

P: n/a
Robert Gamble wrote:
On Mar 14, 6:10 pm, "Old Wolf" <oldw...@inspire.net.nzwrote:
>Ok, we've had two long and haphazard threads about unions recently,
and I still don't feel any closer to certainty about what is permitted
and what isn't. The other thread topics were "Real Life Unions"
and "union {unsigned char u[10]; ...} ".

Here's a concrete example:

#include <stdio.h>

int main(void)
{
union { int s; unsigned int us; } u;

u.us = 50;
printf("%d\n", u.s);
return 0;
}

Is this program well-defined (printing 50), implementation-defined, or
UB ?

Note that the aliasing rules in C99 6.5 are not violated here -- it is
not forbidden under that section to access an object of some type T
with an lvalue expression whose type is the signed or unsigned
version of T.

In other words, is there anything other than the aliasing rules that
restrict 'free' use of unions?

C89: undefined.
It is undefined because the member of the union accessed is not the
member last stored, this is explicitly stated in the Standard.
Where? 6.3.2.3 says it's implementation-defined (ANSI standard if
it matters).

Yevgen
Mar 15 '07 #6

P: n/a
On Mar 14, 10:32 pm, p...@see.signature.invalid (Pierre Asselin)
wrote:
Old Wolf <oldw...@inspire.net.nzwrote:
[ snip ]
union { int s; unsigned int us; } u;
u.us = 50;
printf("%d\n", u.s);

I was looking at N1124. Annex J lists among the unspecified
behaviors,

-- The value of a union member other than the last one stored
into (6.2.6.1).

Annex J is informative, not normative,
Indeed it is not and in this case it is simply erroneous. The
sentence you cited is leftover from a previous version of the
Standard, there is no supporting text in the Standard proper.
but it still makes sense to
look at section 6.2.6.1 to see why the behavior is unspecified.
You are making the false assumption that 6.2.6.1 actually contains
verbiage to this effect, it doesn't.
There we see that u.s and u.us have object representations as
sequences of unsigned char (paragraphs 2,4), but that some object
representations may be trap representations leading to undefined
behavior when you access u.s (par. 5). Further down, 6.2.6.2(1-2)
leave open the possibility that int has more trap representations
than unsigned int, for example if there are padding bits or if ints
are sign-magnitude and M<N-1 in 6.2.6.2(2).

So it seems that your code has undefined (not just unspecified)
behavior, by 6.2.6.1(5).
I have no idea how you were able to come to that conclusion from
anything you have cited so far. You appear to have come to a
premature conclusion and then tried, unconvincingly, to make the
evidence fit that conclusion.
If you want to read your 50 as a signed int, you need to convert
the bits, e.g. by assignment, u.s= u.us; on a really wicked machine,
that assignment need not be a no-op !

My argument doesn't work the other way. 6.2.6.2(5) says:

A valid (non-trap) object representation of a signed integer
type where the sign bit is zero is a valid object representation
of the corresponding unsigned type, and shall represent
the same value.
The opposite is also true, 6.2.5p9:

"The range of nonnegative values of a signed integer type is a
subrange of the corresponding unsigned integer type, and the
representation of the same value in each type is the same."
so I haven't ruled out
u.s = 50;
printf("%u\n", u.us);

I can't see anything else in 6.2.6.1 that could rule it out, either.
Paragraph 6.2.6.1(7) applies, but I'm pretty sure that sizeof(int)==
sizeof(unsigned int) by 6.2.6.2 so there are no leftover bytes
for (7) to ... bite (D'oh).
Note that the aliasing rules in C99 6.5 are not violated here -- it is
not forbidden under that section to access an object of some type T
with an lvalue expression whose type is the signed or unsigned
version of T.

I don't think that's relevant. It says that the compiler must
assume, for optimization purposes, that u.s and u.us are potentially
aliased (well, duh). For example,

memcpy(buf, &u.us, sizeof(u.us)); /* unsigned char buf[BIG] */
do_something((const unsigned char *)buf);
u.s= 50;
memcpy(buf, &u.us, sizeof(u.us)); /* can't optimize out */
In other words, is there anything other than the aliasing rules that
restrict 'free' use of unions?

As I said, I don't think the aliasing rules matter. Your example
amounts to a C++ reinterpret_cast<intand can hit a trap
representation.
I don't know what C++ has to do with this.

Robert Gamble

Mar 15 '07 #7

P: n/a
Jack Klein wrote:
On 14 Mar 2007 15:10:44 -0700, "Old Wolf" <ol*****@inspire.net.nz>
wrote in comp.lang.c:
>Ok, we've had two long and haphazard threads about unions recently,
and I still don't feel any closer to certainty about what is permitted
and what isn't. The other thread topics were "Real Life Unions"
and "union {unsigned char u[10]; ...} ".

Most of the rambling was caused by the original OP, I think, rather
than the material. I am not criticizing, just observing.
[snip]
There is no difference in aliasing in a union than there is via
pointer casting.
Sorry if it's something obvious or stupid, but please consider this
(no pointers involved).
Suppose double is eight bytes big, int is four bytes, there are
no padding bits in int.

/* (1) get bits from a double and see what happens */
double a = 3.45; unsigned int b;
memcpy(&b, &a, sizeof b);
printf("%u", b);

/* (2) do same thing using a union */
union U {double a; unsigned int b;} u;
u.a = 3.14;
printf("%u", u.b);

/* (3) initialize union with memcpy and access its member */
double d;
union U {double a; unsigned int b;} u;
d = 3.14;
memcpy(&u, &d, sizeof d);
printf("%u", u.b);

Which of three are valid? I think (1) is; (3) maybe; (2) maybe, if
(3) valid and aliasing rules don't work here. If aliasing rules
do apply to (2), then how is first assignment in (2) different
from memcpy() in (3)?

It's in fact the same question as in the other post by OP, about
aliasing. Perhaps all such magic is allowed and that's it. Perhaps
I'm just stupid that I can't understand these simple things.

Yevgen
Mar 15 '07 #8

P: n/a
On Mar 15, 1:20 am, Yevgen Muntyan <muntyan.removet...@tamu.edu>
wrote:
Robert Gamble wrote:
On Mar 14, 6:10 pm, "Old Wolf" <oldw...@inspire.net.nzwrote:
Ok, we've had two long and haphazard threads about unions recently,
and I still don't feel any closer to certainty about what is permitted
and what isn't. The other thread topics were "Real Life Unions"
and "union {unsigned char u[10]; ...} ".
Here's a concrete example:
#include <stdio.h>
int main(void)
{
union { int s; unsigned int us; } u;
u.us = 50;
printf("%d\n", u.s);
return 0;
}
Is this program well-defined (printing 50), implementation-defined, or
UB ?
Note that the aliasing rules in C99 6.5 are not violated here -- it is
not forbidden under that section to access an object of some type T
with an lvalue expression whose type is the signed or unsigned
version of T.
In other words, is there anything other than the aliasing rules that
restrict 'free' use of unions?
C89: undefined.
It is undefined because the member of the union accessed is not the
member last stored, this is explicitly stated in the Standard.

Where? 6.3.2.3 says it's implementation-defined (ANSI standard if
it matters).
It's a mistake in the Standard, it is supposed to be undefined.

Robert Gamble

Mar 15 '07 #9

P: n/a
Robert Gamble wrote:
On Mar 15, 1:20 am, Yevgen Muntyan <muntyan.removet...@tamu.edu>
wrote:
>Robert Gamble wrote:
>>On Mar 14, 6:10 pm, "Old Wolf" <oldw...@inspire.net.nzwrote:
Ok, we've had two long and haphazard threads about unions recently,
and I still don't feel any closer to certainty about what is permitted
and what isn't. The other thread topics were "Real Life Unions"
and "union {unsigned char u[10]; ...} ".
Here's a concrete example:
#include <stdio.h>
int main(void)
{
union { int s; unsigned int us; } u;
u.us = 50;
printf("%d\n", u.s);
return 0;
}
Is this program well-defined (printing 50), implementation-defined, or
UB ?
Note that the aliasing rules in C99 6.5 are not violated here -- it is
not forbidden under that section to access an object of some type T
with an lvalue expression whose type is the signed or unsigned
version of T.
In other words, is there anything other than the aliasing rules that
restrict 'free' use of unions?
C89: undefined.
It is undefined because the member of the union accessed is not the
member last stored, this is explicitly stated in the Standard.
Where? 6.3.2.3 says it's implementation-defined (ANSI standard if
it matters).

It's a mistake in the Standard, it is supposed to be undefined.
So infamous compiler which doesn't strive to C99 compliance could make
the following explode (or Death Station version from 1991 for that
matter)?

union U {int a; unsigned char u[25];};
int main (void)
{
unsigned char c;
union U u;
u.a = 8;
c = u.u[0];
return 0;
}

Perhaps "do not touch union member which wasn't previously set" is
not just a product of my paranoidal mind?

DR's 257, 283, 236 and thread named "Union arrangement" in comp.lang.c
(the end of it) are interesting reading, by the way.
C faq is more loyal to this:

http://www.c-faq.com/struct/union.html
A union is essentially a structure in which all of the fields overlay
each other; you can only use one field at a time. (You can also cheat by
writing to one field and reading from another, to inspect a type's
bit patterns or interpret them differently, but that's obviously pretty
machine-dependent.)

Yevgen
Mar 15 '07 #10

P: n/a
On Thu, 15 Mar 2007 05:55:15 GMT, Yevgen Muntyan
<mu****************@tamu.eduwrote in comp.lang.c:
Jack Klein wrote:
On 14 Mar 2007 15:10:44 -0700, "Old Wolf" <ol*****@inspire.net.nz>
wrote in comp.lang.c:
Ok, we've had two long and haphazard threads about unions recently,
and I still don't feel any closer to certainty about what is permitted
and what isn't. The other thread topics were "Real Life Unions"
and "union {unsigned char u[10]; ...} ".
Most of the rambling was caused by the original OP, I think, rather
than the material. I am not criticizing, just observing.
[snip]
There is no difference in aliasing in a union than there is via
pointer casting.

Sorry if it's something obvious or stupid, but please consider this
(no pointers involved).
You are mistaken, of course there are pointers involved. Just not
pointer objects.
Suppose double is eight bytes big, int is four bytes, there are
no padding bits in int.

/* (1) get bits from a double and see what happens */
double a = 3.45; unsigned int b;
memcpy(&b, &a, sizeof b);
There are two pointers used in the function call statement. The &
operator generates two addresses, which are passed to memcpy() as
pointers to void.
printf("%u", b);
The behavior is undefined.
/* (2) do same thing using a union */
union U {double a; unsigned int b;} u;
u.a = 3.14;
printf("%u", u.b);
The behavior is undefined.
/* (3) initialize union with memcpy and access its member */
double d;
union U {double a; unsigned int b;} u;
d = 3.14;
memcpy(&u, &d, sizeof d);
printf("%u", u.b);
The behavior is undefined.
Which of three are valid? I think (1) is; (3) maybe; (2) maybe, if
(3) valid and aliasing rules don't work here. If aliasing rules
do apply to (2), then how is first assignment in (2) different
from memcpy() in (3)?
None of the three are valid. The standard does not give you
permission to access an lvalue of type unsigned int after writing some
or all of the bits of a double to it.
It's in fact the same question as in the other post by OP, about
aliasing. Perhaps all such magic is allowed and that's it. Perhaps
I'm just stupid that I can't understand these simple things.
I am beginning to wonder if you are being deliberately obtuse. The
only "magic" that is allowed unconditionally is that any object, or
any block of memory belonging to a program, may be read as an array of
unsigned characters without invoking undefined behavior.

There is often a need, even in strictly conforming C code, to access
raw memory regardless of the type of objects it contains. A simple
operation like generating an MD5 signature for a file, for example.

Unsigned char is the one and only "raw" data type in C. It is the one
and only type allowed to read the bytes of any object, and it cannot
trap because every possible combination of bits in a byte is a valid
representation of an unsigned char value.

Read the first five paragraphs of 6.2.6.1 about representation of
types, and the terms "object representation", and "trap
representation".

You, and many other C programmers, seem to think that a union has some
magical properties. It does not. Any aliasing of types you do with a
union can also be done via explicit pointer conversion and
dereference, or implicit pointer conversion as memcpy() does.

If the aliasing is defined by the standard in any one of the three
situations, it is well-defined for all of them. If it is undefined,
but works in an implementation-defined manner on your particular
platform, it will work the same way no matter what method you use to
actually alias it.

There is nothing magical about a union when it comes to type punning,
and all three of your examples cause undefined behavior because they
are omitted from the inclusive list of allowed aliasing in 6.5p7.
There is no mention of reading some or all of the object
representation of a double with an lvalue of type unsigned int.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Mar 16 '07 #11

P: n/a
Robert Gamble <rg*******@gmail.comwrote:
On Mar 14, 10:32 pm, p...@see.signature.invalid (Pierre Asselin)

Annex J is informative, not normative,
Indeed it is not and in this case it is simply erroneous. The
sentence you cited is leftover from a previous version of the
Standard, there is no supporting text in the Standard proper.
Has a defect report been filed ?
[ ... ]
So it seems that [Old Wolf's] code has undefined (not just
unspecified) behavior, by 6.2.6.1(5).
I have no idea how you were able to come to that conclusion from
anything you have cited so far. You appear to have come to a
premature conclusion and then tried, unconvincingly, to make the
evidence fit that conclusion.
Not at all. I was tried to prove from 6.2.6 that O.W. can store
and read the bits of a small positive integer interchangeably
through lvalues of type int and unsigned int, but I could only do
it for the signed --unsigned direction.
My argument doesn't work the other way. 6.2.6.2(5) says:

A valid (non-trap) object representation of a signed integer
type where the sign bit is zero is a valid object representation
of the corresponding unsigned type, and shall represent
the same value.
The opposite is also true, 6.2.5p9:
"The range of nonnegative values of a signed integer type is a
subrange of the corresponding unsigned integer type, and the
representation of the same value in each type is the same."
Indeed. That takes care of the unsigned --signed direction,
especially in view of footnote 31. So Old Wolf's example is
conforming after all.

This looks like a small defect in the standard. Section 6.2.6.1
opens with: "The representations of all types are unspecified except
as stated in this subclause". I took "subclause" to mean 6.2.6.1
itself but that doesn't work. It could concievably mean all of
6.2.6, which is titled "Representations of types", but not 6.2.5 .
Yet 5.2.5(9) is needed to close a loophole.

I don't know what C++ has to do with this.
It spelled out the concept of a bit-preserving cast, as opposed to
C's value-preserving (for the most part) cast.
--
pa at panix dot com
Mar 16 '07 #12

P: n/a
Jack Klein wrote:
On Thu, 15 Mar 2007 05:55:15 GMT, Yevgen Muntyan
<mu****************@tamu.eduwrote in comp.lang.c:
>Jack Klein wrote:
>>On 14 Mar 2007 15:10:44 -0700, "Old Wolf" <ol*****@inspire.net.nz>
wrote in comp.lang.c:

Ok, we've had two long and haphazard threads about unions recently,
and I still don't feel any closer to certainty about what is permitted
and what isn't. The other thread topics were "Real Life Unions"
and "union {unsigned char u[10]; ...} ".
Most of the rambling was caused by the original OP, I think, rather
than the material. I am not criticizing, just observing.
[snip]
>>There is no difference in aliasing in a union than there is via
pointer casting.
Sorry if it's something obvious or stupid, but please consider this
(no pointers involved).

You are mistaken, of course there are pointers involved. Just not
pointer objects.
Um, of course there are pointers. I believe I do understand what &
operator means, and what's passed to memcpy(). I meant something like
"aliasing via pointer casting". If there is this sort of aliasing
involved, *then* I am mistaken.
>Suppose double is eight bytes big, int is four bytes, there are
no padding bits in int.

/* (1) get bits from a double and see what happens */
double a = 3.45; unsigned int b;
memcpy(&b, &a, sizeof b);

There are two pointers used in the function call statement. The &
operator generates two addresses, which are passed to memcpy() as
pointers to void.
>printf("%u", b);

The behavior is undefined.
Why? This line does not access value of a. If anything violates
aliasing rules here, then it's memcpy() call. Does it violate
aliasing rules (I honestly can't see how they are applicable here).
>/* (2) do same thing using a union */
union U {double a; unsigned int b;} u;
u.a = 3.14;
printf("%u", u.b);

The behavior is undefined.
>/* (3) initialize union with memcpy and access its member */
double d;
union U {double a; unsigned int b;} u;
d = 3.14;
memcpy(&u, &d, sizeof d);
printf("%u", u.b);

The behavior is undefined.
>Which of three are valid? I think (1) is; (3) maybe; (2) maybe, if
(3) valid and aliasing rules don't work here. If aliasing rules
do apply to (2), then how is first assignment in (2) different
from memcpy() in (3)?

None of the three are valid. The standard does not give you
permission to access an lvalue of type unsigned int after writing some
or all of the bits of a double to it.
Um, I guess this is the main thing. I can't understand this, since
I can't see the difference between

memcpy(&intvalue, &doublevalue,1);

and

memcpy(charbuf,&doublevalue,1); memcpy(&intvalue,charbuf,1);

This is the thing I can't get: how do bits copied from
an object carry object's type? There is explicit wording
about memcpy() in 6.5p5, but that's only about case
when destination doesn't have effective type.
Does 6.5p6 imply this: "you can read a bit from an object only using
an lvalue of appropriate type, regardless of how far away you carried
that bit using a char array or anything else" (sounds like some
physics to me); and to get it more ridiculous: can you print
bit sequence of a double to the screen, write it down, enter it
back, and initialize an unsigned int using that bit sequence?
>It's in fact the same question as in the other post by OP, about
aliasing. Perhaps all such magic is allowed and that's it. Perhaps
I'm just stupid that I can't understand these simple things.

I am beginning to wonder if you are being deliberately obtuse.
"Magic" was a leftover from extensive editing. Sorry for that.
Read the first five paragraphs of 6.2.6.1 about representation of
types, and the terms "object representation", and "trap
representation".
I said "Suppose double is eight bytes big, int is four bytes, there are
no padding bits in int." No problems with representation. If my examples
are bad, then it's for reasons other than invalid/trap representation.

[snip]

Yevgen
Mar 16 '07 #13

P: n/a
Yevgen Muntyan wrote, On 16/03/07 03:19:
Jack Klein wrote:
>On Thu, 15 Mar 2007 05:55:15 GMT, Yevgen Muntyan
<mu****************@tamu.eduwrote in comp.lang.c:
>>Jack Klein wrote:
On 14 Mar 2007 15:10:44 -0700, "Old Wolf" <ol*****@inspire.net.nz>
wrote in comp.lang.c:

Ok, we've had two long and haphazard threads about unions recently,
and I still don't feel any closer to certainty about what is permitted
and what isn't. The other thread topics were "Real Life Unions"
and "union {unsigned char u[10]; ...} ".
Most of the rambling was caused by the original OP, I think, rather
than the material. I am not criticizing, just observing.
[snip]
There is no difference in aliasing in a union than there is via
pointer casting.
Sorry if it's something obvious or stupid, but please consider this
(no pointers involved).

You are mistaken, of course there are pointers involved. Just not
pointer objects.

Um, of course there are pointers. I believe I do understand what &
operator means, and what's passed to memcpy(). I meant something like
"aliasing via pointer casting". If there is this sort of aliasing
involved, *then* I am mistaken.
>>Suppose double is eight bytes big, int is four bytes, there are
no padding bits in int.

/* (1) get bits from a double and see what happens */
double a = 3.45; unsigned int b;
memcpy(&b, &a, sizeof b);

There are two pointers used in the function call statement. The &
operator generates two addresses, which are passed to memcpy() as
pointers to void.
>>printf("%u", b);

The behavior is undefined.

Why? This line does not access value of a. If anything violates
aliasing rules here, then it's memcpy() call. Does it violate
aliasing rules (I honestly can't see how they are applicable here).
It accesses the bit pattern of (part of a) double as if it was an
unsigned int. That bit pattern might be a trap representation for
unsigned int. As was suggested, look up object and trap representations.
>>/* (2) do same thing using a union */
union U {double a; unsigned int b;} u;
u.a = 3.14;
printf("%u", u.b);

The behavior is undefined.
>>/* (3) initialize union with memcpy and access its member */
double d;
union U {double a; unsigned int b;} u;
d = 3.14;
memcpy(&u, &d, sizeof d);
printf("%u", u.b);

The behavior is undefined.
>>Which of three are valid? I think (1) is; (3) maybe; (2) maybe, if
(3) valid and aliasing rules don't work here. If aliasing rules
do apply to (2), then how is first assignment in (2) different
from memcpy() in (3)?

None of the three are valid. The standard does not give you
permission to access an lvalue of type unsigned int after writing some
or all of the bits of a double to it.

Um, I guess this is the main thing. I can't understand this, since
I can't see the difference between

memcpy(&intvalue, &doublevalue,1);

and

memcpy(charbuf,&doublevalue,1); memcpy(&intvalue,charbuf,1);
There is no difference. In either case accessing intvalue afterwards
invokes undefined behaviour.
This is the thing I can't get: how do bits copied from
an object carry object's type?
They do not. However, what is a valid bit pattern for one type might be
a trap for another.
There is explicit wording
about memcpy() in 6.5p5, but that's only about case
when destination doesn't have effective type.
Does 6.5p6 imply this: "you can read a bit from an object only using
an lvalue of appropriate type, regardless of how far away you carried
that bit using a char array or anything else" (sounds like some
physics to me); and to get it more ridiculous: can you print
bit sequence of a double to the screen, write it down, enter it
back, and initialize an unsigned int using that bit sequence?
You are the one assuming there is some kind of magic going on, there
isn't. There is not guarantee that the bit pattern that is valid for a
double is valid for any other type apart from unsigned char.
>>It's in fact the same question as in the other post by OP, about
aliasing. Perhaps all such magic is allowed and that's it. Perhaps
I'm just stupid that I can't understand these simple things.

I am beginning to wonder if you are being deliberately obtuse.

"Magic" was a leftover from extensive editing. Sorry for that.
>Read the first five paragraphs of 6.2.6.1 about representation of
types, and the terms "object representation", and "trap
representation".

I said "Suppose double is eight bytes big, int is four bytes, there are
no padding bits in int."
The C standard takes in to account implementations where that is not
true, therefore the C standard leave undefined things which might have
an obvious possible definition for a simple implementation you select.

Undefined does not mean is *will* go BANG, only that it is allowed to.
No problems with representation. If my examples
are bad, then it's for reasons other than invalid/trap representation.
Again, you are wrong. All bits 1 is allowed to be a trap representation
for a signed integer type if there are no padding bits and 2s complement
is used. For sign-magnitude and ones complement machines -0 is allowed
to be a trap.

If you are going to exclude all the possible implementations where it
could go wrong then of course you will not see why it is undefined, but
if you allow for the range of implementations that the C standard allows
for then you will see that it makes sense for it to be undefined.
--
Flash Gordon
Mar 16 '07 #14

P: n/a
Flash Gordon wrote:
Yevgen Muntyan wrote, On 16/03/07 03:19:
>Jack Klein wrote:
>>On Thu, 15 Mar 2007 05:55:15 GMT, Yevgen Muntyan
<mu****************@tamu.eduwrote in comp.lang.c:

Jack Klein wrote:
On 14 Mar 2007 15:10:44 -0700, "Old Wolf" <ol*****@inspire.net.nz>
wrote in comp.lang.c:
>
>Ok, we've had two long and haphazard threads about unions recently,
>and I still don't feel any closer to certainty about what is
>permitted
>and what isn't. The other thread topics were "Real Life Unions"
>and "union {unsigned char u[10]; ...} ".
Most of the rambling was caused by the original OP, I think, rather
than the material. I am not criticizing, just observing.
[snip]
There is no difference in aliasing in a union than there is via
pointer casting.
Sorry if it's something obvious or stupid, but please consider this
(no pointers involved).

You are mistaken, of course there are pointers involved. Just not
pointer objects.

Um, of course there are pointers. I believe I do understand what &
operator means, and what's passed to memcpy(). I meant something like
"aliasing via pointer casting". If there is this sort of aliasing
involved, *then* I am mistaken.
>>>Suppose double is eight bytes big, int is four bytes, there are
no padding bits in int.

/* (1) get bits from a double and see what happens */
double a = 3.45; unsigned int b;
memcpy(&b, &a, sizeof b);

There are two pointers used in the function call statement. The &
operator generates two addresses, which are passed to memcpy() as
pointers to void.

printf("%u", b);

The behavior is undefined.

Why? This line does not access value of a. If anything violates
aliasing rules here, then it's memcpy() call. Does it violate
aliasing rules (I honestly can't see how they are applicable here).

It accesses the bit pattern of (part of a) double as if it was an
unsigned int. That bit pattern might be a trap representation for
unsigned int. As was suggested, look up object and trap representations.
....
No problems with representation. If my examples
are bad, then it's for reasons other than invalid/trap representation.

Again, you are wrong. All bits 1 is allowed to be a trap representation
for a signed integer type if there are no padding bits and 2s complement
is used. For sign-magnitude and ones complement machines -0 is allowed
to be a trap.
It was unsigned int. I specifically chose it and assumed no padding bits
in int to avoid problems with representation. I could formulate it in
more verbose ways, for instance wrap every example into an if() which
checks whether there are padding bits, to get pieces of code which
do *not* exhibit UB on any implementation. I did miss possibility of
padding bits in double. Here you go:

#include <limits.h>

#if 1
#define LONGSIZE 4
#else
#define LONGSIZE 8
#endif

unsigned long
kind_of_log2 (unsigned long n)
{
unsigned i;
for (i = 1; n; ++i)
n >1;
return i;
}

int main (void)
{
if (sizeof(int) == 4 && CHAR_BIT == 8 &&
kind_of_log2(UINT_MAX) == 32 &&
( (sizeof(long) == 4 && kind_of_log2(ULONG_MAX) == 32) ||
(sizeof(long) == 8 && kind_of_log2(ULONG_MAX) == 64) ))
{
long a = 1658; unsigned int b;
memcpy(&b, &a, sizeof b);
}
return 0;
}

kind_of_log2() may be wrong here, but it's certainly possible to
write a correct one which would compute number of value bits
(there are even constants for that, right?)
If you are going to exclude all the possible implementations where it
could go wrong then of course you will not see why it is undefined, but
if you allow for the range of implementations that the C standard allows
for then you will see that it makes sense for it to be undefined.
As far as I understand aliasing rules were invented to allow for
optimizations, not to avoid problems with trap representations.
I may be wrong, but rationale doesn't say so, IIRC. Now, does it
make sense for standard to make the code above undefined because
there may be trap representations somewhere?
It may be true, for exactly the reason you say, so standard doesn't
bother to spell out conditions when there are no problems with
trap representation and stuff (it'd be pointless since code like
this is bad). But then what place of the standard makes this
code undefined explicitly? If it doesn't, then 6.2 describes
exactly what happens in the code above (it doesn't tell what
value will be in 'b', that's implementation-defined, and the
program above will tell you).

Best regards,
Yevgen
Mar 16 '07 #15

P: n/a
Jack Klein wrote:
>
.... snip ...
>
There is no difference in aliasing in a union than there is via
pointer casting.
Not so. The compiler is able to insert conversion code to
implement a cast. It is not able to do so for an aliased union.
Which is why it is implementation or undefined behavior to access a
union component as other than the form in which it was stored.

To illustrate, consider a perverse 16 bit machine in which pointers
are machine addresses stored hi order byte first, and integers are
stored low order byte first. How is the compiler to know when to
flip the bytes when accessed through a union?

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
--
Posted via a free Usenet account from http://www.teranews.com

Mar 16 '07 #16

P: n/a
CBFalconer <cb********@yahoo.comwrote:
Jack Klein wrote:
... snip ...

There is no difference in aliasing in a union than there is via
pointer casting.
Not so. The compiler is able to insert conversion code to
implement a cast. It is not able to do so for an aliased union.
Jack said *pointer* casting. I assume he means something like
*((target_type *) &source_var), subject to size and alignment match.
The cast changes the bits of &source_var, but not source_var itself.

--
pa at panix dot com
Mar 16 '07 #17

P: n/a
On Mar 15, 5:25 am, CBFalconer <cbfalco...@yahoo.comwrote:
Jack Klein wrote:

... snip ...
There is no difference in aliasing in a union than there is via
pointer casting.

Not so. The compiler is able to insert conversion code to
implement a cast. It is not able to do so for an aliased union.
Which is why it is implementation or undefined behavior to access a
union component as other than the form in which it was stored.

To illustrate, consider a perverse 16 bit machine in which pointers
are machine addresses stored hi order byte first, and integers are
stored low order byte first. How is the compiler to know when to
flip the bytes when accessed through a union?
DR 283 addresses this by adding a footnote to 6.5.2.3#3 which states:
"If the member used to access the contents of a union object is not
the same as the member last used to store a value in the object, the
appropriate part of the object representation of the value is
reinterpreted as an object representation in the new type as described
in 6.2.6 (a process sometimes called "type punning"). This might be a
trap representation."

Robert Gamble

Mar 18 '07 #18

P: n/a
On Mar 17, 3:13 am, Yevgen Muntyan <muntyan.removet...@tamu.edu>
wrote:
It was unsigned int. I specifically chose it and assumed no padding bits
in int to avoid problems with representation.
#if 1
#define LONGSIZE 4
#else
#define LONGSIZE 8
#endif
Look, none of this matters. The C Standard explicitly says that
it is undefined behaviour to read the bit pattern of a double as
if it were an unsigned int (and vice versa) -- end of story. It
doesn't say "sometimes undefined" or "undefined if size of long
is not 4 blah blah blah".

If you want to question why the Standard says this, or perhaps
suggest the Standard be changed -- the place for that is the
newsgroup comp.std.c .

Mar 18 '07 #19

P: n/a
On Mar 18, 5:36 pm, "Old Wolf" <oldw...@inspire.net.nzwrote:
On Mar 17, 3:13 am, Yevgen Muntyan <muntyan.removet...@tamu.edu>
wrote:
It was unsigned int. I specifically chose it and assumed no padding bits
in int to avoid problems with representation.
#if 1
#define LONGSIZE 4
#else
#define LONGSIZE 8
#endif

Look, none of this matters. The C Standard explicitly says that
it is undefined behaviour to read the bit pattern of a double as
if it were an unsigned int (and vice versa) -- end of story. It
doesn't say "sometimes undefined" or "undefined if size of long
is not 4 blah blah blah".
Where does it say that? Is it aliasing rules or something else?
Because I was suggested here it doesn't matter whether we do

memcpy(&intval, &doubleval, sizeof intval);

or

memcpy(chararray, &doubleval, sizeof intval);
memcpy(&intval, chararray, sizeof intval);

and clearly aliasing rules do not apply to the latter. If it's indeed
aliasing rules, then so be it, it'd be a magic and it'd be fine. In
two posts I was told about trap values, which I take as a possible
explanation of why standard would opt to say something is undefined
(i.e. the reason, the rationale), this is fine. But what exactly place
in the standard says that

unsigned long longval;
unsigned int intval;
/* make sure no trap representation involved */
....
memcpy(&intval, &longval, sizeof intval);

is undefined?

Best regards,
Yevgen

Mar 18 '07 #20

P: n/a
mu*****@gmail.com wrote:
/* make sure no trap representation involved */
How do you propose to do that ?
--
pa at panix dot com
Mar 19 '07 #21

P: n/a
On Mar 18, 6:53 pm, munt...@gmail.com wrote:
On Mar 18, 5:36 pm, "Old Wolf" <oldw...@inspire.net.nzwrote:
On Mar 17, 3:13 am, Yevgen Muntyan <muntyan.removet...@tamu.edu>
wrote:
It was unsigned int. I specifically chose it and assumed no padding bits
in int to avoid problems with representation.
#if 1
#define LONGSIZE 4
#else
#define LONGSIZE 8
#endif
Look, none of this matters. The C Standard explicitly says that
it is undefined behaviour to read the bit pattern of a double as
if it were an unsigned int (and vice versa) -- end of story. It
doesn't say "sometimes undefined" or "undefined if size of long
is not 4 blah blah blah".

Where does it say that? Is it aliasing rules or something else?
Because I was suggested here it doesn't matter whether we do

memcpy(&intval, &doubleval, sizeof intval);

or

memcpy(chararray, &doubleval, sizeof intval);
memcpy(&intval, chararray, sizeof intval);

and clearly aliasing rules do not apply to the latter. If it's indeed
aliasing rules, then so be it, it'd be a magic and it'd be fine. In
two posts I was told about trap values, which I take as a possible
explanation of why standard would opt to say something is undefined
(i.e. the reason, the rationale), this is fine. But what exactly place
in the standard says that

unsigned long longval;
unsigned int intval;
/* make sure no trap representation involved */
...
memcpy(&intval, &longval, sizeof intval);
First off, as far as I can tell, none of your examples violate the
aliasing rules. Second, if the change to the bit-representation of an
object does not result in a trap representation, using the value does
not result in undefined behavior. Determining that the result is not
a trap representation is of course not easy to do in a portable way.

Robert Gamble

Mar 19 '07 #22

P: n/a
On Mar 18, 7:33 pm, "Robert Gamble" <rgambl...@gmail.comwrote:
On Mar 18, 6:53 pm, munt...@gmail.com wrote:
On Mar 18, 5:36 pm, "Old Wolf" <oldw...@inspire.net.nzwrote:
On Mar 17, 3:13 am, Yevgen Muntyan <muntyan.removet...@tamu.edu>
wrote:
It was unsigned int. I specifically chose it and assumed no padding bits
in int to avoid problems with representation.
#if 1
#define LONGSIZE 4
#else
#define LONGSIZE 8
#endif
Look, none of this matters. The C Standard explicitly says that
it is undefined behaviour to read the bit pattern of a double as
if it were an unsigned int (and vice versa) -- end of story. It
doesn't say "sometimes undefined" or "undefined if size of long
is not 4 blah blah blah".
Where does it say that? Is it aliasing rules or something else?
Because I was suggested here it doesn't matter whether we do
memcpy(&intval, &doubleval, sizeof intval);
or
memcpy(chararray, &doubleval, sizeof intval);
memcpy(&intval, chararray, sizeof intval);
and clearly aliasing rules do not apply to the latter. If it's indeed
aliasing rules, then so be it, it'd be a magic and it'd be fine. In
two posts I was told about trap values, which I take as a possible
explanation of why standard would opt to say something is undefined
(i.e. the reason, the rationale), this is fine. But what exactly place
in the standard says that
unsigned long longval;
unsigned int intval;
/* make sure no trap representation involved */
...
memcpy(&intval, &longval, sizeof intval);

First off, as far as I can tell, none of your examples violate the
aliasing rules. Second, if the change to the bit-representation of an
object does not result in a trap representation, using the value does
not result in undefined behavior. Determining that the result is not
a trap representation is of course not easy to do in a portable way.
I posted code which *ensures* there are no problems with
representation. The memcpy() call isn't going to be executed on all
possible implementations, but it's going to be called on some (e.g.
your or mine), and if it's called then there are no problems with
representation [1].

So you are saying it's fine to copy bits from double to an int *given*
no representation problems happen. If I messed up in the last
sentence, then this one: my example with kind_of_log2 is strictly-
conforming (after you fix obvious mistake in kind_of_log2 and perhaps
other mistakes I didn't notice).

The post I replied to said "it's UB because standard explicitly says
so". I guess I am not the only one confused by this stuff.

Yevgen

Mar 19 '07 #23

P: n/a
On Mar 15, 10:20 pm, Jack Klein <jackkl...@spamcop.netwrote:
On Thu, 15 Mar 2007 05:55:15 GMT, Yevgen Muntyan
<muntyan.removet...@tamu.eduwrote in comp.lang.c:
Jack Klein wrote:
On 14 Mar 2007 15:10:44 -0700, "Old Wolf" <oldw...@inspire.net.nz>
wrote in comp.lang.c:
>Ok, we've had two long and haphazard threads about unions recently,
>and I still don't feel any closer to certainty about what is permitted
>and what isn't. The other thread topics were "Real Life Unions"
>and "union {unsigned char u[10]; ...} ".
Most of the rambling was caused by the original OP, I think, rather
than the material. I am not criticizing, just observing.
[snip]
There is no difference in aliasing in a union than there is via
pointer casting.
Sorry if it's something obvious or stupid, but please consider this
(no pointers involved).

You are mistaken, of course there are pointers involved. Just not
pointer objects.
Suppose double is eight bytes big, int is four bytes, there are
no padding bits in int.
/* (1) get bits from a double and see what happens */
double a = 3.45; unsigned int b;
memcpy(&b, &a, sizeof b);

There are two pointers used in the function call statement. The &
operator generates two addresses, which are passed to memcpy() as
pointers to void.
printf("%u", b);

The behavior is undefined.
/* (2) do same thing using a union */
union U {double a; unsigned int b;} u;
u.a = 3.14;
printf("%u", u.b);

The behavior is undefined.
/* (3) initialize union with memcpy and access its member */
double d;
union U {double a; unsigned int b;} u;
d = 3.14;
memcpy(&u, &d, sizeof d);
printf("%u", u.b);

The behavior is undefined.
Which of three are valid? I think (1) is; (3) maybe; (2) maybe, if
(3) valid and aliasing rules don't work here. If aliasing rules
do apply to (2), then how is first assignment in (2) different
from memcpy() in (3)?

None of the three are valid. The standard does not give you
permission to access an lvalue of type unsigned int after writing some
or all of the bits of a double to it.
C&V please.

Robert Gamble

Mar 19 '07 #24

P: n/a
On Mar 19, 10:53 am, munt...@gmail.com wrote:
On Mar 18, 5:36 pm, "Old Wolf" <oldw...@inspire.net.nzwrote:
Look, none of this matters. The C Standard explicitly says that
it is undefined behaviour to read the bit pattern of a double as
if it were an unsigned int (and vice versa) -- end of story. It
doesn't say "sometimes undefined" or "undefined if size of long
is not 4 blah blah blah".

Where does it say that?
C99 6.5#6 and 6.5#7 .
Is it aliasing rules
Yes
Because I was suggested here it doesn't matter whether we do

memcpy(&intval, &doubleval, sizeof intval);
or
memcpy(chararray, &doubleval, sizeof intval);
memcpy(&intval, chararray, sizeof intval);
Those two both have the same effect, if chararray is big enough.
and clearly aliasing rules do not apply to the latter.
Actually they do. (See below)
But what exactly place in the standard says that

unsigned long longval;
unsigned int intval;
/* make sure no trap representation involved */
...
memcpy(&intval, &longval, sizeof intval);

is undefined?
It isn't undefined. The behaviour is only undefined if you
subsequently
evaluate the value of 'intval'. The reason it is undefined at that
point
is because of the aliasing rules: you are using an 'unsigned int'
lvalue
to access a bit pattern that is (part of) the bit pattern of a
different
type (namely, unsigned long).

'trap representation' also does not come into it unless you evaluate
intval. Memory is just memory, you can write whatever crap you want
into it. Problems only arise when you try and treat said crap as if
you are expecting a valid value.

Mar 19 '07 #25

P: n/a
On Mar 18, 11:07 pm, "Old Wolf" <oldw...@inspire.net.nzwrote:
On Mar 19, 10:53 am, munt...@gmail.com wrote:
On Mar 18, 5:36 pm, "Old Wolf" <oldw...@inspire.net.nzwrote:
Look, none of this matters. The C Standard explicitly says that
it is undefined behaviour to read the bit pattern of a double as
if it were an unsigned int (and vice versa) -- end of story. It
doesn't say "sometimes undefined" or "undefined if size of long
is not 4 blah blah blah".
Where does it say that?

C99 6.5#6 and 6.5#7 .
Is it aliasing rules

Yes
Because I was suggested here it doesn't matter whether we do
memcpy(&intval, &doubleval, sizeof intval);
or
memcpy(chararray, &doubleval, sizeof intval);
memcpy(&intval, chararray, sizeof intval);

Those two both have the same effect, if chararray is big enough.
and clearly aliasing rules do not apply to the latter.

Actually they do. (See below)
But what exactly place in the standard says that
unsigned long longval;
unsigned int intval;
/* make sure no trap representation involved */
...
memcpy(&intval, &longval, sizeof intval);
is undefined?

It isn't undefined. The behaviour is only undefined if you
subsequently
evaluate the value of 'intval'. The reason it is undefined at that
point
is because of the aliasing rules: you are using an 'unsigned int'
lvalue
to access a bit pattern that is (part of) the bit pattern of a
different
type (namely, unsigned long).
6.5p6 starts out:
"An object shall have its stored value accessed only by an lvalue
expression that has one of
the following types:"

"access" is defined as "to read or modify the value of an object".
According to your logic, the following would invoke undefined
behavior:

union {int i; float f;} u;
u.f = 1.2;
u.i = 10;

That seems pretty silly.

Robert Gamble

Mar 19 '07 #26

P: n/a
On Mar 18, 10:07 pm, "Old Wolf" <oldw...@inspire.net.nzwrote:
On Mar 19, 10:53 am, munt...@gmail.com wrote:
On Mar 18, 5:36 pm, "Old Wolf" <oldw...@inspire.net.nzwrote:
Look, none of this matters. The C Standard explicitly says that
it is undefined behaviour to read the bit pattern of a double as
if it were an unsigned int (and vice versa) -- end of story. It
doesn't say "sometimes undefined" or "undefined if size of long
is not 4 blah blah blah".
Where does it say that?

C99 6.5#6 and 6.5#7 .
6.5p6 only says that after 'unsigned b;' effective type of b is
unsigned.

It's not obviouos that 6.5p7 talks about any access to the value at
any time
(access as in "look at what is *or was* inside the object"). Say, we
can take a
double, copy it to a character array, print bits to the screen, ask
user to enter
them back, and then set individual bits in an unsigned value [1]. We
*can* set any
bits we like in an unsigned, it's just arithmetic operations.

If character array here is important and aliasing rules stop working
after copying
into a character array, then it contradicts to what you said below. If
aliasing
rules stop after we ask user to enter value, then it's *magic* (we
could write
sequence of 0 and 1 characters to a file for that matter).
>
Is it aliasing rules

Yes
Because I was suggested here it doesn't matter whether we do
memcpy(&intval, &doubleval, sizeof intval);
or
memcpy(chararray, &doubleval, sizeof intval);
memcpy(&intval, chararray, sizeof intval);

Those two both have the same effect, if chararray is big enough.
Yevgen

[1] This is not necessarily some simple arithmetic operation like
uint_val = uchar_array[0] + (1u<<CHAR_BIT)*uchar_array[0] + ...
of course; but we can get the mapping from unsigned value bits to bits
in unsigned char array by simply looking at the result of
unsigned foo = 1u << n;
memcpy(&char_array, &foo, sizeof foo);
It assumes absence of padding bits (which we *may* assume).

Mar 19 '07 #27

This discussion thread is closed

Replies have been disabled for this discussion.