Keith said:
john said:
Keith Thompson wrote: [...]
Note that the implementation doesn't keep track for you of which
member of the union is currently active. It's up to you do to that
yourself, or to deal with the consequences if you read one member
after writing a different one.
I believe you are wrong about this
I don't believe so.
consider this example...
main()
{
union { char a; long int b; } u[10];
memset(u, 'x', 10 * sizeof *u);
u[0].a = 'a';
u[1].b = 0;
printf("%s\n", u);
}
On gcc, this yields
./prog
axxxxxxx
You appear to have ignored a number of compile-time warnings.
So let's consider this example:
#include<stdio.h>
#include<string.h>
int main(void)
{
union { char a; long int b; } u[10];
memset(u, 'x', sizeof u);
u[0].a = 'a';
u[1].b = 0;
printf("%s\n", (char*)u);
return 0;
}
which yields the same output without quite so much undefined behavior.
But it still treats an array of unions as if it were a string. What is
this intended to demonstrate? Just what do you think is happening here,
and how does it contradict what I wrote above?
The problem is that it just doesn't make sense to have an array of
inconsistent types.
Right, which is why it's not possible in C.
Possibly the code above was not the best example. I believe the code
below shows the problem more clearly...
print_chars(const char *p)
{
auto int i;
This may be the first time I've seen the `auto' keyword used
except as an obfuscatory device.
for(i=0;i<4;i++) printf("%c",*p++);
}
main()
{
union { char a; long int b; } u[10];
memset(u, 'x', 10 * sizeof *u);
u[0].a = 'a';
u[1].a = 'b';
u[2].a = 'c';
u[3].a = 'd';
print_chars(u);
The compiler should have given you a diagnostic here: The
function parameter is a `const char *' but the argument you provide
is a `union <tagless> *'. The latter does not convert to the former
automatically, so the compiler should have complained. If it didn't,
I suspect you're operating the compiler in a C-ish but not-quite-C
mode, such as the default mode of gcc. (Even so, I'm surprised
that you didn't get at least a warning.)
Had you received a warning (or had you not ignored it if it did
in fact appear), that would/should have alerted you to the fact that
you're doing something suspicious. In particular, you're using a
`char*' to look at the "unspecified values" of the bytes that come
after `u[0].a'. This is legal (more or less) because in C any object
of any type can be viewed as an array of bytes. On the other hand,
there's no guarantee about what sort of output you might get, beyond
the first 'a' -- the values of the other three bytes are unspecified
(they are not even guaranteed to retain their original 'x' values).
putchar('\n');
}
With gcc I get:
./prog
axxx
instead of abcd. Arrays of unions are not sensible even when the types
are consistent!
An array of big-fat-unions-that-happen-to-hold-chars is not
an array of chars (except in the special sense mentioned earlier).
An array of big-fat-unions-that-happen-to-hold-shorts is not an
array of shorts.
Here's an analogy, perhaps not a good one but maybe it will
help. I show you a row of ten shipping cartons, each a one-foot
cube. You put a packet of breath mints in each carton, and the
tiny little packet fits into a carton with lots of room left over
so you also put in some bubble wrap to keep things from rattling
around.
All ten cartons are lined up on the floor, each abutting its
neighbors with no space in between. I point at the breath mints
in carton [0], and ask "How far is it from this packet of mints
to the next?" Here are two possible answers:
1) "The mint packet is three inches long, so the next mint
packet must be three inches away."
2) "The box holding the mint packet is a foot long and the
next packet is in the next box, so it's a foot away."
Right now, you seem to be leaning toward answer (1) -- which means
your career as a shipping clerk will be short and inglorious. ;-)