[net.lang.c] Initialization of unions under ANSI C

hokey@plus5.UUCP (Hokey) (10/23/84)

I asked why unions were initialized using the first element, and received
this reply:

> From: wucs!seismo!harvard!wjh12!kendall
> To: plus5!hokey
> Subject: ANSI initialization of unions
> References: <504@plus5.UUCP>
> 
> The ANSI C rule for initialization of unions (use the first member)
> is there because there is no syntax for indicating which member of a
> union you want to initialize.
> 
> 	Sam Kendall	  {allegra,ihnp4,ima,amd}!wjh12!kendall
> 	Delft Consulting Corp.	    decvax!genrad!wjh12!kendall

My point is, it doesn't matter.  If the data used to initialize the
union is appropriately cast, and that data type is a valid member of
the union, then there is no ambiguity nor problem; the union will hold
the value by definition, and the data will be appropriately cast.

Note that there is no ambiguity even when initializing a list of items
inside a union: the initializer-list could be cast, or the first element
of the list could be cast.

The following is *not* a well-thought-out example.  Please bear with me:

	#define CHAR	01
	#define SHORT	02
	#define LONG	03
	#define FLOAT	04
	#define DOUBLE	05
	#define SHORT_A	06

	struct {	/* I know it doesn't have a name */
	    int	CellType;	/* holds one of the above defines */
	    union {
		char	cv_char;
		short	cv_short;
		long	cv_long;
		float	cv_float;
		double	cv_double;
		short	cv_short_a[4]
	    } cv;
	} cell[10] = {
	/*0*/ {CHAR,	'?'},	/* cast isn't needed in this case */
	/*1*/ {DOUBLE,	(double)2},
	/*2*/ {SHORT_A,	(short[]){0, 1, 2}}	/* last element is 0? */
	};

Shoot away!  (This is the sort of thing I'd like to discuss in mod.std.c)
-- 
Hokey           ..ihnp4!plus5!hokey
		  314-725-9492

hokey@plus5.UUCP (Hokey) (10/24/84)

> < Note that there is no ambiguity even when initializing a list of items
> < inside a union: the initializer-list could be cast, or the first element
> < of the list could be cast.
> 
> Dennis himself pointed out immediately this example when given the above
> argument a year and a half ago at a standards meeting:
> 
> union {
>     char *x;
>     char y[4];
>     } = "abc";
> 
> The string "abc" can represent either a character string to initialize the
> array y or it can represent a character pointer to represent the pointer x,
> depending on the context. Considering that both contexts are valid in this
> place, some rule is necessary. The rule of "first listed in the union"
> would mean that it would initialize the pointer. If you wanted the array
> initialized, how would you specify it with casts? There is no way currently,
> but it is easy to do with ANSI C by just listing the array first.
> 
> 					Tony Hansen
> 					pegasus!hansen

So cast it. (No hidden pun...)  Use this instead:

union {
    char *x;
    char y[4];
    } Strange[] = {
	(char[]) "abc",		/* This is an array of characters (y) */
	(char *) "abc"		/* This is a pointer to a character */
    };

Did you read the last comment above?  All (char *) does is "permit" one
to reference the object to which it points *as a character*.  There is
no guarantee regarding the veracity of the object "at the end of the rainbow"
or the objects surrounding the item referenced by the pointer.  Do I need
to go on about this point?

As near as I can tell, initialization of tables is the biggest pain.  These
tables need to be initialized to useful data.  I would hate to see a portion
of a table initialized at compile time and the rest of it initialized at
run time!  I, for one, would rarely bother to initialize unions at compile
time because I almost always want the union portions of the tables filled
with data befitting the table entry.  The proposed initialization rule
seems weak to me.

Both replies to my posting were cases where there was an ambiguity in the
interpretation of the initializer (the other reply asked about the case in
which a union of an int and a float was initialized to "2").

I am one of those apparently rare people who explicitly declares or casts
Everything.  (Well, almost.  I usually specify the "length" to malloc, read,
and write using an int because I never let the data lengths get that big;
the data in these cases is invariably string, and all the string functions
use ints.)  I wish the C compiler would help people like me, and warn me
about implicit declarations and conversions.  I don't care if I have to add
a switch to CFLAGS (although I would prefer strict checking as the default,
and make the lazy people specify a switch to provide "lax" checking).

Explicit declarations seem to solve the problem of arbitrary initialization
of unions.  Could somebody point out an example where casting initializers
won't work?
-- 
Hokey           ..ihnp4!plus5!hokey
		  314-725-9492