Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

casting to a union

1 view
Skip to first unread message

alan l wendt

unread,
Dec 12, 1989, 7:46:39 PM12/12/89
to
Apologies if this has come up before; I don't follow this group.

I have a function that accepts either char pointers or ints as
arguments, so I declare it with unions,

union numstr {
int i;
char *s;
};

void foo( union numstr ns ) { ... }


Why can't I call it as follows:

foo((union numstr)7);

Presumably foo knows which it is getting by some external means.
This seems easy and innocuous, but I don't think the language
will let me do it.
Probably if this were allowed in, the backwards conversion would
also be allowed, i.e. from (union numstr) to (int). That would
be ok with me, too; I actually prefer "(int)ns" to "ns.i".
Can anybody think of a reason not to allow this?

Alan Wendt

Chris Torek

unread,
Dec 13, 1989, 1:33:27 AM12/13/89
to
In article <34...@ccncsu.ColoState.EDU> we...@handel.cs.colostate.edu

(alan l wendt) writes:
>I have a function that accepts either char pointers or ints as
>arguments, so I declare it with unions,

(probably a mistake---have two different functions, or make it a variadic
function; it will make life easier)

>union numstr {
> int i;
> char *s;
> };
>
>void foo( union numstr ns ) { ... }
>
>Why can't I call it as follows:
>
> foo((union numstr)7);

No casts to or from aggregate types are allowed in C. (GCC allows
some such casts; this is an extension.) In particular, there is a
large semantic problem: which element(s) of the union get the value?
The simplistic answer---that the union element which has the same type
as the argument---is not sufficient. A better answer is to declare
that a cast to some type is semantically equivalent to declaring a
variable of that type, and initialising it with the value(s) being
cast, and returning the (rvalue of) the variable. This would allow
aggregate casts and give them well-defined meanings:

struct foo { int i; char c; short *s; double d; };
... (struct foo) { 1, 'a', &myshort, 3.14159265 } ...

Unfortunately, K&R 1 disallows all aggregate initialisers except
in static (compile-time constant) contexts, and most useful places
for casts are not such. The proposed ANSI standard allows more,
but says that union initialisers are for the first element only.
Hence

(union numstr) expr

would (under this proposal) set only the first element of the
temporary `union numstr' `variable'.

>Probably if this were allowed in, the backwards conversion would
>also be allowed, i.e. from (union numstr) to (int).

Here the semantic gap is even worse. What is the value of

struct foo { /* as above */ } x;
(char *)x

? What about

union numstr ns;
(void *) ns

? Which element did you want?

The usual answer at this point (yes, this is one of the many repeating
comp.lang.c topics) is that the element of the union which should be
chosen for the cast is the one which has the same type as the thing
being cast. This has two problems: (a) there may be no same type; (b)
there may be more than one `same' type, differing only in object types,
not in value types. For instance:

union junk { int i; short s; };
char c;
f ( (union junk)c );

`c' is a char; its rvalue type is `int', so we could set either i or s,
both of which will hold all possible `char' values. It does make a
difference which is chosen, as if `s' is set, some parts of `i' may be
uninitialised (full of junk). Now take a harder case:

union junk { struct foo st; double d[2]; };
f ( (union junk){ 1, 2.5 } );

Is this putting the 1 and 2.5 into foo.i (an int) and foo.c (a char), or
is it putting the 1 and 2.5 into d[0] and d[1]? They all fit---that is,
they are all assignment compatible---but neither match types exactly, and
it is far from clear which is meant.
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain: ch...@cs.umd.edu Path: uunet!mimsy!chris

Bill Poser

unread,
Dec 13, 1989, 2:42:04 AM12/13/89
to
Perhaps the simplest point to note about why (union numstr) 7
is no good is to keep in mind that unions really are aggregates.
It is easy to fall into the trap of thinking of a union as a type
abstraction, so that a union that can hold either a character point
or an integer is a type that is one or the other, but that isn't
the case from C's point of view. Rather, a union is an aggregate
just like a struct except for the fact that the members share storage.
So the reason you can't cast 7 to (union numstr) is the same reason that
you can't cast it to a struct or an array.
0 new messages