Why is this allowed in C?

B

Bryan Bullard

Is this allowed in ANSI C? My compiler says it's okay. If so, what is the
point of using enum instead of #define?

typedef enum
{
ONE = 1,

TWO = 2,

THREE = 3
} NUMBERS;


int main()
{
NUMBERS num = 5;

return 0;
}

TIA,
Bryan
 
M

Michael Mair

Hi there,
Is this allowed in ANSI C? My compiler says it's okay. If so, what is the
point of using enum instead of #define?

typedef enum
{
ONE = 1,

TWO = 2,

THREE = 3
} NUMBERS;


int main()
{
NUMBERS num = 5;

return 0;
}

NUMBERS is a type which can have the values of all enumeration constants
you specified in your enum (and all the values in between).
An enumeration does _not_ provide a means to specify a set of values
which variables of the type can take on -- which probably is the
functionality you hoped for.
What you _can_ do, however, is using enumeration constants like symbolic
constants without having to care about the value. If you want to have,
for example, a means to distinguish between different cases but do not
care about the numbers behind the constants, you just use an enumeration

enum dc { firstcase, secondcase, thirdcase, fourthcase };

If you add a fifth case, you do not have to look for a new number to
assign to it but just use it.
Think of it as a convenient way of obtaining valid constants no two
of which are equal (if you do not wish it).

The discussion you find under
http://groups.google.com/groups?th=430152de91554ce3
may give you some additional ideas.

I like using C99 designated initializers along with enumerations,
e.g.

.....
/* Usage: Enter new sorting algorithm in list of algos after creating
** an enum entry.
*/

/* Enumeration of possible sorting algos */
typedef enum sortingalgos {START=-1,
selection,
insertion,
bubble,
shell,
quick,
LAST
} Counter;

/* Function pointer type for sorting algos */
typedef int (* MySortProcPtr) (int *, size_t);

/* Structure containing all algo information */
typedef struct {
char algochar; // I/O identifier
char *algoname; // Name to be printed
MySortProcPtr algofunc; // Function pointer
} SortingInfo;

/* Actual list; global for convenience */
static SortingInfo MyInfo[] = {
[selection] = {'s', "selection sort" , selectionsort},
[insertion] = {'i', "insertion sort" , insertionsort},
[bubble] = {'b', "bubble sort" , bubblesort},
[shell] = {'S', "Shell sort" , shellsort},
[quick] = {'q', "quick sort"
" (recursive,"
" middle of three,"
" insertion sort)" , quicksort}
};
.....

You loop with a Counter variable from START+1 to <END to search
for the identifiers, print the name, call the function but still
are able to handle exceptions by checking for the corresponding
enumeration constant. Using the designated initializer with the
constant makes sure that you never ever check for the wrong array
index...


Cheers
Michael
 
E

Eric Sosman

Bryan said:
Is this allowed in ANSI C? My compiler says it's okay. If so, what is the
point of using enum instead of #define?

typedef enum
{
ONE = 1,
TWO = 2,
THREE = 3
} NUMBERS;

int main()
{
NUMBERS num = 5;
return 0;
}

Yes, it's legitimate. An enum type is merely an
alias for some flavor of integer (the compiler gets to
choose which), and since 5 is within the range of every
integer type, the initialization is valid.

Some languages -- Pascal is one, IIRC -- provide true
enumerated types, in which the only valid values for a
NUMBERS object would be ONE, TWO, and THREE. But C's enum
types are less restrictive and (perhaps) less powerful:
All you get is the aforementioned alias for some kind of
integer plus suggestive names for the listed `int' values.

Are there advantages over #define'd constants? A few,
perhaps, but they're not very compelling. One is the
"automatic numbering" of the constants:

typedef enum { EINS = 1, ZWEI, DREI } ZAHLEN;

defines ZWEI as 2 and DREI as 3 without your needing to
state it explicitly -- not much of a savings in a list as
short as this one, but a convenience with larger lists.
Another (and this isn't really a C language issue) is that
some debuggers keep track of the constant names and will
display an `enum color' value as AQUAMARINE instead of 42;
I've never encountered a debugger that could do this with
#define'd constants.

See also Question 2.22 in the comp.lang.c Frequently
Asked Questions (FAQ) list

http://www.eskimo.com/~scs/C-faq/top.html
 
D

Dan Pop

In said:
Is this allowed in ANSI C? My compiler says it's okay.

It's right. That's one of the reasons C is not considered a strongly
typed language.
If so, what is the point of using enum instead of #define?

1. Friendlier syntax, the compiler can do the numbering for you.

2. Preprocessor macros are gone after the preprocessing stage. This is
important in two occasions: you're using a debugger and you're
reading already preprocessed code. Both occur during program
debugging. It makes quite a difference between seeing an unadorned
arbitrary integer constant (say 3) and seeing an enumeration constant
like VALVE_OPEN.

Dan
 
R

Richard Tobin

Eric Sosman said:
Are there advantages over #define'd constants? A few,
perhaps, but they're not very compelling. One is the
"automatic numbering" of the constants:
Another (and this isn't really a C language issue) is that
some debuggers keep track of the constant names and will
display an `enum color' value as AQUAMARINE instead of 42;

Another is that some compilers will warn if a switch statement doesn't
cover all the cases of an enumeration. I've found that annoying
more often than useful, but maybe one day it will catch a bug I
would have spent hours tracking down otherwise.

-- Richard
 
B

Bryan Bullard

Bryan Bullard said:
Is this allowed in ANSI C? My compiler says it's okay. If so, what is the
point of using enum instead of #define?

....

Thanks everyone.
 
D

Dave Thompson

In <[email protected]> "Bryan Bullard" <[email protected]> writes:

1. Friendlier syntax, the compiler can do the numbering for you.
And enums are restricted to ints, while #define'd macros can be long
etc., floating-point, strings, and indeed any (sequence of) tokens.
2. Preprocessor macros are gone after the preprocessing stage. This is
important in two occasions: you're using a debugger and you're
reading already preprocessed code. <snip>

Also, macros effectively prevent any other use of the same name, which
is why it is conventional to make (many) macros all-uppercase so you
won't accidently conflict. enum values are ordinary identifiers and do
not conflict with tags or locally-scoped variables or parameters.
Which again may be what you want, or not.

- David.Thompson1 at worldnet.att.net
 
I

Ivan A. Kosarev

Also, macros effectively prevent any other use of the same name, which
is why it is conventional to make (many) macros all-uppercase so you
won't accidently conflict. enum values are ordinary identifiers and do
not conflict with tags or locally-scoped variables or parameters.
Which again may be what you want, or not.

Locally-scoped variables are declaring as ordinary identifiers too.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top