Перечисление — это набор именованных целых констант. Перечисления довольно часто встречаются в повседневной жизни. Вот, например, перечисление, в котором приведены названия монет, используемых в Соединенных Штатах:
penny (пенни, монета в один цент), nickel (никель, монета в пять центов), dime (монета в 10 центов), quarter (25 центов, четверть доллара), half-dollar (полдоллара), dollar (доллар)
Перечисления определяются во многом так же, как и структуры; началом объявления перечислимого типа[1] служит ключевое слово enum. Перечисление в общем виде выглядит так:
enum тег {список перечисления} список переменных;
Здесь тег и список переменных не являются обязательными. (Но хотя бы что-то одно из них должно присутствовать.) Следующий фрагмент кода определяет перечисление с именем coin (монета):
enum coin { penny, nickel, dime, quarter,
half_dollar, dollar};
Тег перечисления можно использовать для объявления переменных данного перечислимого типа. Вот код, в котором money (деньги) объявляется в качестве переменной типа coin:
enum coin money;
С учетом этих объявлений совершенно верными являются следующие операторы:
money = dime;
if(money==quarter) printf("Денег всего четверть доллара.\n");
Главное, что нужно знать для понимания перечислений — каждый их элемент[2] представляет целое число. В таком виде элементы перечислений можно применять везде, где используются целые числа. Каждому элементу дается значение, на единицу большее, чем у его предшественника. Первый элемент перечисления имеет значение 0. Поэтому, при выполнении кода
printf("%d %d", penny, dime);
на экран будет выведено 0 2.
Однако для одного или более элементов можно указать значение, используемое как инициализатор. Для этого после перечислителя надо поставить знак равенства, а затем — целое значение. Перечислителям, которые идут после инициализатора, присваиваются значения, большие предшествующего. Например, следующий код присваивает quarter значение 100:
enum coin { penny, nickel, dime, quarter=100,
half_dollar, dollar};
вот какие значения появились у этих элементов:
penny 0
nickel 1
dime 2
quarter 100
half_dollar 101
dollar 102
Относительно перечислений есть одно распространенное, но ошибочное мнение. Оно состоит в том, что их элементы можно непосредственно вводить и выводить. Это не так. Например, следующий фрагмент кода не будет выполняться так, как того ожидают многие неопытные программисты:
/* этот код работать не будет */
money = dollar;
printf("%s", money);
Здесь dollar — это имя для значения целого типа; это не строка. Таким образом, попытка вывести money в виде строки по существу обречена. По той же причине для достижения нужных результатов не годится и такой код:
/* этот код не правильный */
strcpy(money, "dime");
То есть строка, содержащая имя элемента, автоматически в этот перечислитель не превратится.
На самом же деле создавать код для ввода и вывода элементов перечислений — это довольно-таки скучное занятие (но его можно избежать лишь тогда, когда будет достаточно именно целых значений этих перечислителей). Например, чтобы выводить название монеты, вид которой находится в money, потребуется следующий код:
switch(money) {
case penny: printf("пенни");
break;
case nickel: printf("никель");
break;
case dime: printf("монета в 10 центов");
break;
case quarter: printf("четверть доллара");
break;
case half_dollar: printf("полдоллара");
break;
case dollar: printf("доллар");
}
Иногда можно объявить строчный массив и использовать значение перечисления как индекс при переводе этого значения в соответствующую строку. Например, следующий код также выводит нужную строку:
char name[][12]={
"пенни",
"никель",
"монета в 10 центов",
"четверть доллара",
"полдоллара",
"доллар"
};
printf("%s", name[money]);
Конечно, он будет работать только тогда, когда не инициализирован ни один из элементов перечисления, так как строчный массив должен иметь индекс, который начинается с 0 и возрастает каждый раз на 1.
Так как при операциях ввода/вывода необходимо специально заботиться о преобразовании перечислений в их строчный эквивалент, который можно легко прочитать, то перечисления полезнее всего именно в тех процедурах, где такие преобразования не нужны. Например, перечисления часто применяются, чтобы определить таблицы соответствия символов в компиляторах.
[1] Иногда используется термин перечисляемый тип.
[2]Элементы списка перечисления называются также перечислителями и идентификаторами.