Structs, Enums, and Unions
From:     http://www.lysator.liu.se/c/c-faq/index.html#EoPS




Section 9. Structs, Enums, and Unions

9.1: What is the difference between an enum and a series of preprocessor
#defines?

At the present time, there is little difference.  Although many people
might
have wished otherwise, the ANSI standard says that enumerations may be
freely intermixed with integral types, without errors.  (If such
intermixing
were disallowed without explicit casts, judicious use of enums could catch
certain programming errors.)

Some advantages of enums are that the numeric values are automatically
assigned, that a debugger may be able to display the symbolic values when
enum variables are examined, and that they obey block scope.  (A compiler
may also generate nonfatal warnings when enums and ints are
indiscriminately
mixed, since doing so can still be considered bad style even though it is
not strictly illegal).  A disadvantage is that the programmer has little
control over the size (or over those nonfatal warnings).

References: K&R II Sec. 2.3 p. 39, Sec. A4.2 p. 196; H&S Sec. 5.5 p. 100;
ANSI Secs. 3.1.2.5, 3.5.2, 3.5.2.2 .

9.2: I heard that structures could be assigned to variables and passed to
and from functions, but K&R I says not.

What K&R I said was that the restrictions on struct operations would be
lifted in a forthcoming version of the compiler, and in fact struct
assignment and passing were fully functional in Ritchie's compiler even as
K&R I was being published.  Although a few early C compilers lacked struct
assignment, all modern compilers support it, and it is part of the ANSI C
standard, so there should be no reluctance to use it.

References: K&R I Sec. 6.2 p. 121; K&R II Sec. 6.2 p. 129; H&S Sec. 5.6.2 p.
103; ANSI Secs. 3.1.2.5, 3.2.2.1, 3.3.16 .

9.3: How does struct passing and returning work?

When structures are passed as arguments to functions, the entire struct is
typically pushed on the stack, using as many words as are required. 
(Programmers often choose to use pointers to structures instead, precisely
to avoid this overhead.)

Structures are often returned from functions in a location pointed to by an
extra, compiler-supplied "hidden" argument to the function.  Some older
compilers used a special, static location for structure returns, although
this made struct-valued functions nonreentrant, which ANSI C disallows.

References: ANSI Sec. 2.2.3 p. 13.

9.4: The following program works correctly, but it dumps core after it
finishes.  Why?

	struct list
		{
		char *item;
		struct list *next;
		}

	/* Here is the main program. */

	main(argc, argv)
	...

A missing semicolon causes the compiler to believe that main returns a
structure.  (The connection is hard to see because of the intervening
comment.)  Since struct-valued functions are usually implemented by adding a
hidden return pointer, the generated code for main() tries to accept three
arguments, although only two are passed (in this case, by the C start-up
code).  See also question 17.21.

References: CT&P Sec. 2.3 pp. 21-2.

9.5: Why can't you compare structs?

There is no reasonable way for a compiler to implement struct comparison
which is consistent with C's low-level flavor.  A byte-by-byte comparison
could be invalidated by random bits present in unused "holes" in the
structure (such padding is used to keep the alignment of later fields
correct; see questions 9.10 and 9.11).  A field-by- field comparison would
require unacceptable amounts of repetitive, in-line code for large
structures.

If you want to compare two structures, you must write your own function to
do so.  C++ would let you arrange for the == operator to map to your
function.

References: K&R II Sec. 6.2 p. 129; H&S Sec. 5.6.2 p. 103; ANSI Rationale
Sec. 3.3.9 p. 47.

9.6: How can I read/write structs from/to data files?

It is relatively straightforward to write a struct out using fwrite:

                fwrite((char *)&somestruct, sizeof(somestruct), 1, fp);

and a corresponding fread invocation can read it back in. However, data
files so written will not be very portable (see questions 9.11 and 17.3).
Note also that on many systems you must use the "b" flag when fopening the
files.
9.7: I came across some code that declared a structure like this:

	struct name
		{
		int namelen;
		char name[1];
		};

and then did some tricky allocation to make the name array act like it had
several elements.  Is this legal and/or portable?

This technique is popular, although Dennis Ritchie has called it
"unwarranted chumminess with the C implementation."  An ANSI Interpretation
Ruling has deemed it (more precisely, access beyond the declared size of
the
name field) to be not strictly conforming, although a thorough treatment of
the arguments surrounding the legality of the technique is beyond the scope
of this list.  It seems, however, to be portable to all known
implementations.  (Compilers which check array bounds carefully might issue
warnings.)

To be on the safe side, it may be preferable to declare the variable-size
element very large, rather than very small; in the case of the above
example:

                ...
                char name[MAXSIZE];
                ...

where MAXSIZE is larger than any name which will be stored. (The trick so
modified is said to be in conformance with the Standard.)

References: ANSI Rationale Sec. 3.5.4.2 pp. 54-5.

9.8: How can I determine the byte offset of a field within a structure?

ANSI C defines the offsetof macro, which should be used if available; see
.
 If you don't have it, a suggested implementation is

	#define offsetof(type, mem) ((size_t) \
		((char *)&((type *) 0)->mem - (char *)((type *) 0)))

This implementation is not 100% portable; some compilers may legitimately
refuse to accept it.

See the next question for a usage hint.

References: ANSI Sec. 4.1.5, Rationale Sec. 3.5.4.2 p. 55.

9.9: How can I access structure fields by name at run time?

Build a table of names and offsets, using the offsetof() macro. The offset
of field b in struct a is

	offsetb = offsetof(struct a, b)

If structp is a pointer to an instance of this structure, and b is an int
field with offset as computed above, b's value can be set indirectly with

	*(int *)((char *)structp + offsetb) = value;

9.10: Why does sizeof report a larger size than I expect for a structure
type, as if there was padding at the end?

Structures may have this padding (as well as internal padding; see also
question 9.5), so that alignment properties will be preserved when an array
of contiguous structures is allocated.

9.11: My compiler is leaving holes in structures, which is wasting space
and
preventing "binary" I/O to external data files.  Can I turn off the
padding,
or otherwise control the alignment of structs?

Your compiler may provide an extension to give you this control (perhaps a
#pragma), but there is no standard method.  See also question 17.3.

9.12: Can I initialize unions?

ANSI Standard C allows an initializer for the first member of a union. 
There is no standard way of initializing the other members (nor, under a
pre
-ANSI compiler, is there generally any way of initializing any of them).

9.13: How can I pass constant values to routines which accept struct
arguments?

C has no way of generating anonymous struct values.  You will have to use a
temporary struct variable.