Wouldn’t it be nice if you could define a variable and specify the valid values that could be stored into that variable? For example, suppose you had a variable called myColor and you wanted to use it to store one of the primary colors, red, yellow, or blue, and no other values. This type of capability is provided by the enumerated data type.
An enumerated data type definition is initiated by the keyword enum. Immediately following this keyword is the name of the enumerated data type, followed by a list of identifiers (enclosed in a set of curly braces) that define the permissible values that can be assigned to the type. For example, the statement
enum primaryColor { red, yellow, blue };
defines a data type primaryColor.Variables declared to be of this data type can be assigned the values red, yellow, and blue inside the program, and no other values. That’s the theory anyway! An attempt to assign another value to such a variable causes some compilers to issue an error message. Other compilers simply don’t check.
To declare a variable to be of type enum primaryColor, you again use the keyword enum, followed by the enumerated type name, followed by the variable list. So the statement
enum primaryColor myColor, gregsColor;
defines the two variables myColor and gregsColor to be of type primaryColor. The only permissible values that can be assigned to these variables are the names red, yellow, and blue. So statements such as
myColor = red;
and
if ( gregsColor == yellow )
…
are valid. As another example of an enumerated data type definition, the following defines the type enum month, with permissible values that can be assigned to a variable of this type being the months of the year:
enum month { january, february, march, april, may,
june, july, august, september, october, november, december };
The C compiler actually treats enumeration identifiers as integer constants. Beginning with the first name in the list, the compiler assigns sequential integer values to these names, starting with 0. If your program contains these two lines:
enum month thisMonth;
…
thisMonth = february;
the value 1 is assigned to thisMonth (and not the name february) because it is the sec- ond identifier listed inside the enumeration list.
If you want to have a specific integer value associated with an enumeration identifier, the integer can be assigned to the identifier when the data type is defined. Enumeration identifiers that subsequently appear in the list are assigned sequential integer values beginning with the specified integer value plus 1. For example, in the definition
enum direction { up, down, left = 10, right };
an enumerated data type direction is defined with the values up, down, left, and right. The compiler assigns the value 0 to up because it appears first in the list; 1 to down because it appears next; 10 to left because it is explicitly assigned this value; and 11 to right because it appears immediately after left in the list.
Program 14.1 shows a simple program using enumerated data types. The enumerated data type month sets january to 1 so that the month numbers 1 through 12 correspond to the enumeration values january, february, and so on. The program reads a month number and then enters a switch statement to see which month was entered. Recall that enumeration values are treated as integer constants by the compiler, so they’re valid case values. The variable days is assigned the number of days in the specified month, and its value is displayed after the switch is exited. A special test is included to see if the month is February.
Program 14.1 Using Enumerated Data Types
// Program to print the number of days in a month
#include <stdio.h>
int main (void)
{
enum month { january = 1, february, march, april, may, june,
july, august, september, october, november, december };
enum month aMonth;
int days;
printf (“Enter month number: “);
scanf (“%i”, &aMonth);
switch (aMonth ) {
case january:
case march:
case may:
case july:
case august:
case october:
case december:
days = 31;
break;
case april:
case june:
case september:
case november:
days = 30;
break;
case february:
days = 28;
break;
default:
printf (“bad month number\n”);
days = 0;
break;
}
if ( days != 0 )
printf (“Number of days is %i\n”, days);
if ( amonth == february )
printf (“…or 29 if it’s a leap year\n”);
return 0;
}
Program 14.1 Output
Enter month number: 5
Number of days is 31
Program 14.1 Output (Rerun)
Enter month number: 2
Number of days is 28
…or 29 if it’s a leap year
Enumeration identifiers can share the same value. For example, in
enum switch { no=0, off=0, yes=1, on=1 };
assigning either the value no or off to an enum switch variable assigns it the value 0;
assigning either yes or on assigns it the value 1.
Explicitly assigning an integer value to an enumerated data type variable can be done with the type cast operator. So if monthValue is an integer variable that has the value 6, for example, the expression
thisMonth = (enum month) (monthValue – 1);
is permissible and assigns the value 5 to thisMonth.
When writing programs with enumerated data types, try not to rely on the fact that the enumerated values are treated as integers. Instead, try to treat them as distinct data types. The enumerated data type gives you a way to associate a symbolic name with an integer number. If you subsequently need to change the value of that number, you must change it only in the place where the enumeration is defined. If you make assumptions based on the actual value of the enumerated data type, you defeat this benefit of using an enumeration.
The variations permitted when defining an enumerated data type are similar to those permitted with structure definitions: The name of the data type can be omitted, and variables can be declared to be of the particular enumerated data type when the type is defined. As an example showing both of these options, the statement
enum { east, west, south, north } direction;
defines an (unnamed) enumerated data type with values east, west, south, or north, and declares a variable direction to be of that type.
Enumerated type definitions behave like structure and variable definitions as far as their scope is concerned: Defining an enumerated data type within a block limits the scope of that definition to the block. On the other hand, defining an enumerated data type at the beginning of the program, outside of any function, makes the definition global to the file.
When defining an enumerated data type, you must make certain that the enumeration identifiers are unique with respect to other variable names and enumeration identifiers defined within the same scope.
Source: Kochan Stephen G. (2004), Programming in C: A Complete Introduction to the C Programming Language, Sams; Subsequent edition.