C Урок 24. Перечисляемый тип. Директива typedef



В уроке 13 мы познакомились с константами, как они объявляются и используются в программе. Мы помним, что это такие данные, которые в ходе программы изменить невозможно и они сохраняют своё значения до окончания своего существования.

Только может наступить такая ситуация, что констант программе потребуется слишком много и под них потребуется слишком много имён и, самое главное, слишком много значений. В таких значениях мы в конце концов запутаемся и рискуем объявить несколько констант с одним и тем же значением. Тогда, скорей всего, неизбежны ошибки, если эти константы будут использоваться для какой-то одной задачи. Конечно, можно объявить константный массив, но тогда не будет уникальных имён под каждый элемент, а по индексу порой не совсем понятно, что значит тот или иной элемент и для чего он будет служить в нашей программе.

Оказывается, что для такой ситуации также есть решение. Это перечисляемый тип для констант, который позволяет нам объявить для какой-то одной задачи сразу несколько констант с уникальными именами, не заботясь об уникальности их значений. Для объявления перечисляемого типа или, как его попросту называют, перечисления служит вот такая конструкция

 

 

Это общая форма конструкции enum. Данная конструкция, обозначающая перечисляемый тип, начинается с ключевого слова enum, Затем следует имя перечисляемого типа, а далее идёт блок, в котором через запятую перечисляются имена констант, причём можно данным константам присвоить значение целого типа сразу, а если его не присвоить (квадратные скобки означают то, что параметры необязательные и могут отсутствовать), то оно присвоится автоматически. Данное значение тогда будет равно значению предыдущей константы в данном списке, увеличенному на единицу. Если мы даже самой первой константе в списке также не присвоим значение, то оно примет значение — 0 (ноль).

Вот так практически мы можем объявить перечисляемый тип

 

enum eColor

{

  COLOR_BLUE,

  COLOR_GREEN,

  COLOR_RED,

};

 

Так как здесь мы ничего не присваиваем нашим элементам перечисления, которые, кстати, называются перечислителями, то их значения будут 0, 1 и 2.

После такого объявления мы можем объявлять переменные с такими именами в нашей программе, только перед именем типа данных нужно будет обязательно писать ключевое слово enum

 

enum eColor clr;

 

Думаю, что более понятно вам станет по данному типу тогда, когда мы его проработаем практически в исходном коде.

Теперь #typegef. Как известно, в языке C любые данные имеют какой-то тип. Каждый такой тип имеет своё имя, например, int, float и т.д. Также порой бывают такие моменты, когда нам нужно объявить в нашем коде какой-то свой тип и присвоить ему какое-то имя. Для этого и служит директива #typedef.

С помощью данной директивы мы можем дать стандартному типу данных своё имя, для этого существует вот такая общая форма объявления пользовательского типа данных

 

 

Например, мы хотим типу float назначить какое-то своё имя

 

typedef float double_32;

 

После данного объявления имя double_32 станет именем типа данных такого же, как и float и его спокойно можно будет использовать в программе

 

double_32 d1;

d1 = 0.01;

 

Например, и перечисление мы тоже можем объявить через typedef

 

typedef enum

{

   SMALL,

   MIDDLE,

   HIGH,

   HIGHEST

} eSize;

 

Теперь имя типа данных перечисляемого типа у нас будет после блока и объявлять в коде переменные данного типа мы можем теперь без ключевого слова enum

 

eSize var_Size = HIGH;

 

Хотя, в принципе, ничего сложного в сегодняшней теме, вроде бы и нет, но всё же, считаю, что проработать её на практике мы просто обязаны.

 

 

Поэтому создадим проект из проекта прошлого урока с именем MYPROG23 и назовём его MYPROG24.

 

 

 

Как создавать проекты из других, не запортив оригинальные, мы с вами научились в прошлом уроке.

Откроем наш проект в eclipse, настроим его таким же образом, как мы делали в прошлом занятии, откроем файл main.c и объявим первый перечисляемый тип, который будет перечислять различные цвета

 

 

В функции main() закомментируем незакомментированный участок кода и в самом начале объявим переменную в программе и присвоим ей какой-нибудь цвет

 

 

Думаю, что мы прекрасно знаем, что присвоить цвет мы можем и на этапе объявления.

Теперь выведем в консоль значение нашей константы в обычном целом виде

 

 

Посмотрим, как это сработает

 

 

Всё прекрасно сработало. Нашей константе присвоилось число, соответствующее по списку. Попробуем следующий цвет

 

clr = COLOR_YELLOW;

 

Соберём и посмотрим на результат

 

 

 

Но только я недаром присвоил одному из цветов ноль, чтобы проверить, как это сработает, поэтому выберем теперь цвет, который расположен в нашем типе после данного элемента-перечислителя

 

clr = COLOR_LIGHTYELLOW;

 

Проверим

 

 

Всё работает. Порой нам эта возможность присваивания нестандартных значений бывает очень нужна для того, чтобы организовать какие-то диапазоны значений, идущие не подряд.

Объявим ещё один перечисляемый тип

 

 

Интересное объявление, не правда ли? Здесь нет даже имени типа. Так тоже, оказывается, делать можно, а иногда и полезно. В данном случае мы можем использовать имена перечислителей данного перечисления как обычные константы, объявленные через директиву #define. Разница будет в том, что будет работать автоматика присвоения значений нашим константам. Попробуем в main() вывести значения данных констант и увидеть, как это работает, закомментировав перед этим наш предыдущий код

 

 

Проверим работу данного кода

 

Всё отлично!

Теперь немного отвлечёмся от перечислений и попробуем объявить свой тип

 

 

В функции main() объявим переменную нашего пользовательского типа и выведем её изменяющиеся значения в цикле, закомментировав предварительно предыдущий код

 

 

Проверим, как работает наш новый тип

 

Тип работает отлично, ничем не хуже, чем обычный беззнаковый int.

Вернёмся к нашим перечислениям, чтобы немного соединить наши две темы.

Вот это перечисление закомментируем

 

 

Вместо него добавим подобное, но уже с именем, причём присвоенным при помощи директивы typedef

 

 

Объявим переменную данного типа в main(), закомменитровав перед этим предыдущий код

 

 

Как мы видим, в этом случае мы уже ключевое слово enum не используем.

Попробуем вывести значения всех наших констант данного типа, используя оператор вариантов

 

 

Проверим, как это сработает

 

 

Всё сработало.

Присвоим другое значение нашей переменной

 

eSize var_Size = SMALL;

 

Проверим, как это будет работать

 

 

Также всё отлично срабатывает.

Объявим ещё один перечисляемый тип аналогичным образом

 

 

Пусть это будут какие-то, скажем, уровни в игре.

В main() закомментируем предыдущий код, объявим переменную нашего нового типа и попробуем перечислить значения всех уровней в цикле

 

 

Проверим работу нашего цикла

 

 

Всё также прекрасно работает.

Но тут возникает вопрос, ведь это же константный тип, каким образом мы в цикле присваиваем ему различные значения? Вот такая вот особенность, что хоть тип и константный, но значения ему присваивать в ходе программы можно, причём это никак не контролируется, мы можем присвоить данной переменной любые целочисленные значения. Всё потому, что константный тип у перечислителей, а у самого перечисления он int, поэтому фактически, когда мы объявляем переменную типа нашего перечисления, то мы её объявляем типа int. Но для восприятия это очень удобно и не даёт нам запутаться. Своего рода, синтаксический сахар.

Таким образом, сегодня мы познакомились с перечисляемым типом, а также с возможностью объявлять в программе пользовательские типы данных. Также мы познакомились с рядом особенностей перечислений и увидели всё это в работе исходного кода нашего проекта.

Всем спасибо за внимание!

 

 

Предыдущий урок Программирование на C Следующий урок

 

Исходный код

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

C Пеоечисляемый тип. Директива typedef

2 комментария на “C Урок 24. Перечисляемый тип. Директива typedef
  1. Юрий:

    вероятно, под #typedef вы имели в виду просто typedef?
    это ключевое слово, а не директива компилятора.
    и еще, явную опечатку- typegef — встретил.

  2. Сергей:

    Не пойму, а что конкретно делает операция eSize var_Size = HIGH? Указывает, что значение переменной равно HIGH? Оно вроде 2 должно быть? Как тогда switch срабатывает?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*