Structures

 ************************************************************
*  Some examples of structure and union usage.               *
*  NB: In ANSI C, structures can be passed by value.         *
 ************************************************************



struct record {
     char id[10];
     char name[30];
     ...
     } str;

In order to point to zero or more instances of `struct record', `fields'
must have the type `pointer to struct record', i.e.,

	struct record *fields;
	fields = &str;

If you wish, you can get the compiler to choose the size, in certain
limited circumstances:

	char *ptrs[] = { str.id, str.name };

(Note that the type of `ptrs' here will be `array 2 of pointer to char',
NOT `array SIZE_UNKNOWN of pointer to char'.  It's worth always noting
the size, even if you have to note that you do not know it, or that you
do not need to know it [which is often true].)

You can then make `fields' point to the first (or rather, 0'th) element
of the array `ptrs'.  Because a pointer that points to the first of a
series of contiguous objects (often called `an array') can be used to
access *any one* (at a time) of those objects, this will be useful after
all.  You will have to give fields a type that points to a pointer-to-char:

	char **fields;
	fields = ptrs;

---------------------------------------------------------------------- 
>   union g {long xx; struct half yy;} *b;

Note that you define a tag "g" here.  Note that any other union or struct
that "happens" to look like it does not have to *really* be implemented
identically, *UNLESS* you reuse the tag!  (I assume you have defined
"half" somewhere else).  If you have severely different expectations, you
should take them up with the ANSI C Committee, as I believe this is in
keeping with the standard.

...
>   	union {long xx; struct half yy;} sum;

Here you define another union, but you did *NOT* use the tag "g".  As a
result, the compiler has the freedom to "optimize" the layout of these
distinct unions.  *IF* you had simply said "union g sum;" you probably
would be safe (unless there was a real bug in the compiler).  In the form
given here, all bets are off in terms of guarantees of compatibility of
the two union types.  My guess is that the optimizing compiler realized
that you had declared a local union, and placed the elements individually
in a convenient place on the stack or in registers.  A lot of folks use
unions to sneakily cast from one data type to another, but there are very
few guarantees that such attempts will work!

Moral of the story:

1) Use function prototypes and the compiler would have given you an
error message, rather than a subtle bug.

2) Avoid the use of casts.  Avoid the use of unions to hide the
fact that you were wanted to use casts.

3) Optimizers are pretty clever.  

4) If you define the same value twice in a program, you are asking for
trouble.  Generally such redefinitions get out of sync.  Even if they
"look the same", they might not be.  It is better to work to reuse a
single definition.  This was an interesting extreme example of two
definitions "looking the same".

---------------------------------------------------------------------