[comp.std.c] enums

bright@Data-IO.COM (Walter Bright) (07/19/88)

From reading the grammar for enums in the Ansi spec, it seems that the
following is not allowed:

	enum abc { };		/* empty member list	*/
	enum def { b, };	/* trailing comma	*/

Many compilers accept this, and I've run across code that uses it. Any
thoughts? Is this an oversight in the spec?

karzes@mfci.UUCP (Tom Karzes) (07/20/88)

While on the subject of enums, here's something that's always bothered me.
If you define an enum with a long list of values, a natural thing to want
to do is determine the number of values in the enum (sort of like sizeof).

For example:

    enum tree {
        oak,
        elm,
        maple,
        birch,
        willow,
        cypress,
        spruce
    };

Now I'd like to define TREE_COUNT to be the number of trees.  So I have to
painfully count them, and write:

    #define TREE_COUNT 7

and hope that people correctly update this macro every time they add or
delete a tree.

Sure, I suppose in this case I could write:

    #define TREE_COUNT ((int) spruce + 1)

(This assumes that there aren't any trees which have been given explicit
values in the enum.)  But this is still a pain to maintain, since you
have to fix the macro every time the last tree changes.

Of course, in the presence of enum members which are given explicit values
(which also introduces the possibility of duplicate values), you may want
to know something more than just the number of members (e.g., the number
of distinct values, the minimum and maximum values, etc.).  However, for
most situations it would be sufficient to simply know the number of members
in the enum.

Does ANSI C provide a reasonable way to do this?

jmd@granite.dec.com (John Danskin) (07/20/88)

In article <469@m3.mfci.UUCP> karzes@mfci.UUCP (Tom Karzes) writes:
>While on the subject of enums, here's something that's always bothered me.
>For example:
>    enum tree {
>        oak,
...
>        spruce
>    };
>
>Now I'd like to define TREE_COUNT to be the number of trees.  So I have to
>painfully count them, and write:
>    #define TREE_COUNT 7
>
>and hope that people correctly update this macro every time they add or
>delete a tree.
>
>Sure, I suppose in this case I could write:
>
>    #define TREE_COUNT ((int) spruce + 1)
>
>(This assumes that there aren't any trees which have been given explicit
>values in the enum.)  But this is still a pain to maintain, since you
>have to fix the macro every time the last tree changes.

Why don't you just write:
    enum tree {
        oak,
        elm,
        maple,
        birch,
        willow,
        cypress,
        spruce,
	NUM_TREES
    };

#define TREE_COUNT ((int)NUM_TREES)

?











You still have a problem with enums with assigned values, but hey, if you
are assigning your own values to enums you had better go have a look at
all of your macros every time you change anything anyway.


-- 
John Danskin				| decwrl!jmd
DEC Technology Development		| (415) 853-6724 
100 Hamilton Avenue			| My comments are my own.
Palo Alto, CA  94306			| I do not speak for DEC.

bill@proxftl.UUCP (T. William Wells) (07/21/88)

In article <469@m3.mfci.UUCP> karzes@mfci.UUCP (Tom Karzes) writes:
) While on the subject of enums, here's something that's always bothered me.
) If you define an enum with a long list of values, a natural thing to want
) to do is determine the number of values in the enum (sort of like sizeof).
)
) For example:
)
)     enum tree {
)         oak,
)         elm,
)         maple,
)         birch,
)         willow,
)         cypress,
)         spruce
)     };
)
) Now I'd like to define TREE_COUNT to be the number of trees.  So I have to
) painfully count them, and write:
)
)     #define TREE_COUNT 7
)...
) Does ANSI C provide a reasonable way to do this?

ANSI is irrelevant. Do it like

	enum tree {
		oak, elm, maple, birch, willow, cypress, spruce,
	tree_size};

#define TREE_COUNT ((int)tree_size)

unless you don't need the cast, in which case, just do this:

	enum tree {
		oak, elm, maple, birch, willow, cypress, spruce,
	TREE_COUNT};

hugh@dgp.toronto.edu ("D. Hugh Redelmeier") (07/25/88)

In article <1608@dataio.Data-IO.COM> bright@Data-IO.COM (Walter Bright) writes:
>From reading the grammar for enums in the Ansi spec, it seems that the
>following is not allowed:
>
>	enum abc { };		/* empty member list	*/
>	enum def { b, };	/* trailing comma	*/
>
>Many compilers accept this, and I've run across code that uses it. Any
>thoughts? Is this an oversight in the spec?

I submitted a comment on the trailing comma during the first public
review period.  So it isn't an oversight, but I do think that it is
a mistake.  I am not sure how I feel about empty enums (perhaps a
good definition for void might be: "typedef void enum {};" :-).
Here is my comment:

Section 3.5.2.3, page 54, line 17 [of the then-current draft]

I think that an enumerator-list should be optionally terminated by a
comma.  This is analogous to the way an initializer is optionally
terminated by a comma (3.5.6 61@21).  The benefits are similar (a
terminator is less error-prone than a separator (consider Pascal's
semicolon)).

This is currently legal in the two compilers I use (the Ritchie
compiler (the original implementation of enum, so it should carry
some weight), and System V VAX UNIX PCC).  I do use the feature.

Hugh Redelmeier
{utcsri, utzoo, yunexus, hcr}!redvax!hugh
In desperation: hugh@csri.toronto.edu
+1 416 482 8253

bright@Data-IO.COM (Walter Bright) (07/26/88)

In article <8807242307.AA27481@explorer.dgp.toronto.edu> hugh@dgp.toronto.edu ("D. Hugh Redelmeier") writes:
<In article <1608@dataio.Data-IO.COM< bright@Data-IO.COM (Walter Bright) writes:
<<From reading the grammar for enums in the Ansi spec, it seems that the
<<following is not allowed:
<<	enum abc { };		/* empty member list	*/
<<	enum def { b, };	/* trailing comma	*/
<<Many compilers accept this, and I've run across code that uses it. Any
<<thoughts? Is this an oversight in the spec?
<This is currently legal in the two compilers I use (the Ritchie
<compiler (the original implementation of enum, so it should carry
<some weight), and System V VAX UNIX PCC).  I do use the feature.

I solved the problem in my compiler by allowing it unless the strict
ANSI switch is thrown. Ah well, more warts!

karl@haddock.ISC.COM (Karl Heuer) (07/27/88)

In article <1608@dataio.Data-IO.COM> bright@Data-IO.COM (Walter Bright) writes:
>[ANSI C seems not to allow:]
>	enum abc { };		/* empty member list	*/
>	enum def { b, };	/* trailing comma	*/

I can see why one might want to allow the trailing comma, but what good is an
enum with no values?  I think this is almost in the same category as
zero-sized objects.  (I.e., the rule that allows small-valued enums to be
stored in a char could be logically extended to allow non-valued enums to be
stored in a zero-size type.)

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

maart@cs.vu.nl (Maarten Litmaath) (07/28/88)

In article <5514@haddock.ISC.COM> karl@haddock.isc.com (Karl Heuer) writes:
\In article <1608@dataio.Data-IO.COM> bright@Data-IO.COM (Walter Bright) writes:
\>[ANSI C seems not to allow:]
\>	enum abc { };		/* empty member list	*/
\>	enum def { b, };	/* trailing comma	*/
\
\I can see why one might want to allow the trailing comma, but what good is an
\enum with no values?

Such code could perhaps be generated by a code generator program?
(#ifdef, #define, etc.)
-- 
If you enjoyed the recent heat wave,  |Maarten Litmaath @ Free U Amsterdam:
you'll certainly like the ozone gap...|maart@cs.vu.nl, mcvax!botter!maart

rbutterworth@watmath.waterloo.edu (Ray Butterworth) (07/28/88)

In article <5514@haddock.ISC.COM>, karl@haddock.ISC.COM (Karl Heuer) writes:
> In article <1608@dataio.Data-IO.COM> bright@Data-IO.COM (Walter Bright) writes:
> >[ANSI C seems not to allow:]
> >	enum abc { };		/* empty member list	*/
> >	enum def { b, };	/* trailing comma	*/
> 
> I can see why one might want to allow the trailing comma, but what good is an
> enum with no values?  I think this is almost in the same category as
> zero-sized objects.  (I.e., the rule that allows small-valued enums to be
> stored in a char could be logically extended to allow non-valued enums to be
> stored in a zero-size type.)

Exactly.
It's been pointed out before that if enums with no values were allowed,
one could simply use:
#typedef enum {} void;
and not need void as part of the language.

It would then be obvious why any other pointer could be cast to a (void*)
since obviously (void*) needs the finest resolution,
and it would be obvious why trying to subscript a void* would be
useless (vs[7] would have a size of 7*sizeof(void)  which is 7*0),
and why a function returning void doesn't really return anything,
or rather that what it returns is something that was already known
before the function was called and one can't do anything with it anyway.

franzen@infbs.UUCP (Marco Franzen) (08/03/88)

In article <5514@haddock.ISC.COM>, karl@haddock.ISC.COM (Karl Heuer) writes:
> I can see why one might want to allow the trailing comma, but what good is an
> enum with no values?  I think this is almost in the same category as
> zero-sized objects.  (I.e., the rule that allows small-valued enums to be
> stored in a char could be logically extended to allow non-valued enums to be
> stored in a zero-size type.)

Even a one-valued enum can be stored in a zero-sized type (i.e. ld 1
bits, calculate ld 0 and enjoy the storage you win :-).  You can get
an Algol68ish void with:

typedef enum { EMPTY } VOID;	/* EMPTY is the only value of type VOID */

But then there is no guarantee for sizeof(VOID)==0, not even for
sizeof(VOID)<=sizeof(char). (In this enum {} wouldn't be better, you
only needn't become Algol68ish.)