View Categories

Перечисления enum

enum #

Есть ещё один способ создания именованных констант - enum (enumeration, перечисление). Он позволяет не просто создать список констант, но и автоматически присвоить им численные значения с шагом 1, начиная с 0. Синтаксис такой:

enum имя_списка {
    константа1,     // значение 0
    константа2,     // значение 1
    константа3,     // значение 2
    // ...
};

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

После объявления enum можно создавать переменные и константы этого нового типа по его названию. Эти переменные могут принимать указанные в списке значения:

имя_списка переменная = константа2;
const имя_списка константа = константа3;

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

Тип данных #

По умолчанию под капотом нашего нового типа данных находится int:

enum Foo {
    foo1,
    foo2,
};

sizeof(Foo);    // соответствует int (2/4 байта)

Foo foo = foo1;
sizeof(foo);    // соответствует int (2/4 байта)

Можно указать конкретный тип вручную как enum имя_списка : тип:

enum Foo : uint8_t {
    foo1,
    foo2,
};

sizeof(Foo);    // 1 байт

Foo foo = foo1;
sizeof(foo);    // 1 байт

Указание значения #

Значения констант в enum можно указывать явно, например кодов цветов:

  • Если константа не задана явно, её значение будет равно значению предыдущей константы + 1
  • Имена должны быть уникальными в рамках перечисления
  • Имена подчиняются правилам создания имён
enum Colors {
    Red = 0xcb2839,
    Orange = 0xd55f30,
    Yellow = 0xd69d27,

    color1,     // 0xd69d28 = Yellow + 1
    color2,     // 0xd69d29 = color1 + 1

    color3 = 1234,
    color4,     // 1235
    //color4,   // ошибка, такое имя уже есть
    //for,      // ошибка, ключевое слово
};

Компилятор автоматически повысит тип данных, если хоть одно значение выходит за int - тип Colors из примера выше является 4-байтным, т.к. 2 байта не хватило бы для хранения указанных чисел (для AVR, int 2 байта)

sizeof(Colors);     // 4 байта

Подсказки значений #

К константе можно обратиться как напрямую - константа, так и через имя списка при помощи оператора :: - имя_списка::константа:

enum Colors {
    Red = 0xcb2839,
    Orange = 0xd55f30,
    Yellow = 0xd69d27,
};

Colors color = Colors::Red;

IDE, в которых есть автодополнение кода, подскажут список констант при вводе имя_списка:::

file

Пересечение имён #

Константы обычного enum доступны глобально для всего кода как обычные числа, их имена могут пересекаться с остальными именами переменных в программе:

int Red;    // #1

enum Colors {
    Red,        // ошибка, имя уже занято переменной #1 выше
    Orange,
    Yellow,     // #2
};

int Yellow;     // ошибка, имя занято #2 в enum выше

Константы enum могут преобразовываться в соответствующие им числа:

int color1 = Orange;            // 1
int color2 = Colors::Orange;    // 1

В крупном проекте или при использовании в библиотеках очень сложно соблюдать уникальность имён констант - приходится добавлять им некрасивые префиксы. Для решения этой проблемы существует enum class.

Enum class #

Это тот же enum, но его константы:

  • "Спрятаны" (инкапсулированы) внутри имени типа, обратиться к ним можно только через ::
  • Не пересекаются с остальной программой
  • Не могут быть автоматически преобразованы и присвоены к обычным переменным. Принудительно - могут
int Red;

enum class Colors {
    Red,        // ошибки нет
    Orange,
    Yellow,
};

int Yellow;     // ошибки нет

int color1 = Orange;                // ошибка, такой константы нет
int color2 = Colors::Orange;        // ошибка, нельзя присвоить к int
int color3 = (int)Colors::Orange;   // так можно, но не нужно

Colors color3 = Colors::Orange;     // нужно так

Если нужно указать конкретный тип такому перечислению - это делается так:

enum class Colors : uint32_t {
    // ...
};

Рекомендуется использовать enum class - он удобнее и безопаснее, сводит количество возможных конфликтов имён практически в ноль

Количество констант #

В C/C++ невозможно узнать из программы количество констант, которое задано в enum или enum class. Но есть трюк, который работает, если все константы нумеруются автоматически с нуля (без задания вручную) - численное значение последней константы всегда равно количеству остальных констант! Просто создаём в конце константу с именем, которое олицетворяет длину списка, и можно пользоваться:

enum class MyConst {
    someConst,  // 0
    const2,     // 1
    Red,        // 2
    green,      // 3
    _len,       // 4 - количество констант (не включая эту)
};

int enumLen = (int)MyConst::_len;   // == 4
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Прокрутить вверх