Spec-Zone.ru › C

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

Тип перечисления — это отдельный тип, значение которого является значением его основного типа (см. ниже), включающего значения явно указанных констант (констант перечисления).

Синтаксис

Тип перечисления объявляется с помощью следующего спецификатора перечисления в качестве спецификатора типа в грамматике объявления:

enum attr-spec-seq (необязательно) идентификатор (необязательно) { список_перечислителей } (1)
enum attr-spec-seq (необязательно) идентификатор (необязательно) : тип { список_перечислителей } (2) (с C23)
1) Объявляет перечисление без фиксированного основного типа.
2) Объявляет перечисление с фиксированным основным типом тип.

где список_перечислителей — это список перечислителей, разделённых запятыми(с разрешенной запятой в конце)(с C99), каждый из которых имеет вид:

константа_перечисления attr-spec-seq (необязательно) (1)
константа_перечисления attr-spec-seq (необязательно) = выражение_константы (2)

где

идентификатор, константа_перечисления - идентификаторы, введенные этим объявлением
выражение_константы - целочисленное выражение-константа значение которого представимо как значение типа int(до C23). Если перечисление имеет фиксированный базовый тип, представимый как значение тип(с C23)
attr-spec-seq - (C23)необязательный список атрибутов,
  • применяются к всему перечислению, если появляются после enum,
  • применяются к перечислителю, если появляются после константа_перечисления

Как и в случае с struct или union, объявление, которое ввело тип перечисления и одну или несколько констант перечисления, может также объявить одну или несколько переменных этого типа или производного от него типа.

enum color { RED, GREEN, BLUE } c = RED, *cp = &c;
// introduces the type enum color
// the integer constants RED, GREEN, BLUE
// the object c of type enum color
// the object cp of type pointer to enum color

Объяснение

Каждая константа_перечисления, которая появляется в теле спецификатора перечисления, становится целочисленной константой типа int(до C23) в охватывающей области видимости и может быть использована, где требуются целочисленные константы (например, как метка case или как размер массива без VLA).

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

  • ранее объявленный тип, если это повторное объявление той же константы перечисления; или,
  • тип перечисления, для перечисления с фиксированным основным типом; или,
  • int, если нет предыдущих констант перечисления в списке перечислителей и нет явного = с определяющим целочисленным выражением-константой; или,
  • int, если задано явно с = и значение целочисленного выражения-константы представимо как int; или,
  • тип целочисленного выражения-константы, если задано явно с = и если значение целочисленного выражения-константы не представимо как int; или,
  • тип значения из последней константы перечисления с прибавленным 1. Если такое целочисленное выражение-константа приведет к переполнению или зацикливанию значения предыдущей константы перечисления от сложения 1, тип приобретает либо:
    • подходящий по размеру знаковый целочисленный тип (исключая битовые целочисленные типы) способный представить значение предыдущей константы перечисления плюс 1; или,
    • подходящий по размеру беззнаковый целочисленный тип (исключая битовые целочисленные типы) способный представить значение предыдущей константы перечисления плюс 1.

Знаковый целочисленный тип выбирается, если предыдущая константа перечисления, к которой добавляется, является знаковым целочисленным типом. Беззнаковый целочисленный тип выбирается, если предыдущая константа перечисления является беззнаковым целочисленным типом. Если нет подходящего по размеру целочисленного типа, описанного ранее, который может представить новое значение, то у перечисления нет типа, способного представить все его значения.

(с C23)
enum color { RED, GREEN, BLUE } r = RED;
switch(r)
{
case RED:
    puts("red");
    break;
case GREEN:
    puts("green");
    break;
case BLUE:
    puts("blue");
    break;
}

Если константа_перечисления следует за = выражение_константы, её значение равно значению этого выражения-константы. Если константа_перечисления не следует за = выражение_константы, её значение на единицу больше значения предыдущего перечислителя в том же перечислении. Значение первого перечислителя (если он не использует = выражение_константы) равно нулю.

enum Foo { A, B, C = 10, D, E = 1, F, G = F + C };
// A=0, B=1, C=10, D=11, E=1, F=2, G=12

Сам идентификатор, если используется, становится именем типа перечисления в пространстве имён пространстве имён и требует использования ключевого слова enum (если не переопределён с помощью typedef в обычное пространство имён).

enum color { RED, GREEN, BLUE };
enum color r = RED; // OK
// color x = GREEN: // Error: color is not in ordinary name space
typedef enum color color_t;
color_t x = GREEN; // OK

Каждый тип перечисления без фиксированного основного типа(с C23) совместим с одним из: char, знаковым целочисленным типом или беззнаковым целочисленным типом (исключая bool и битовые целочисленные типы)(с C23). Реализация определяет, какой тип совместим с данным типом перечисления, но какой бы он ни был, он должен быть способен представлять все значения перечислителей этого перечисления. Для всех перечислений с фиксированным основным типом тип перечисления совместим с основным типом перечисления.(с C23)

Тип члена перечисления для типа перечисления без фиксированного основного типа после завершения:

  • int, если все значения перечисления представимы как int; или,
  • тип перечисления.
(с C23)
Все перечисления имеют базовый тип. Базовый тип можно явно указать, используя спецификатор типа перечисления, и это его фиксированный базовый тип. Если он не указан явно, базовый тип — это совместимый тип перечисления, который является знаковым или беззнаковым целочисленным типом или char. (с C23)

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

enum { ONE = 1, TWO } e;
long n = ONE; // promotion
double d = ONE; // conversion
e = 1.2; // conversion, e is now ONE
e = e + 1; // e is now TWO

Примечания

В отличие от struct или union, в C нет перечислений с предварительной декларацией:

enum Color; // Error: no forward-declarations for enums in C
enum Color { RED, GREEN, BLUE };

Перечисления позволяют объявить именованные константы более удобным и структурированным способом, чем #define; они видны в отладчике, подчиняются правилам области видимости и участвуют в системе типов.

#define TEN 10
struct S { int x : TEN; }; // OK

или

enum { TEN = 10 };
struct S { int x : TEN; }; // also OK

С C23 constexpr можно использовать для той же цели:

constexpr int TEN = 10;
struct S { int x : TEN; }; // also OK

Кроме того, поскольку struct или union не устанавливают свою область видимости в C, тип перечисления и его константы перечисления могут быть введены в спецификацию члена первого, и их область видимости будет такой же, как и у первого, после этого.

struct Element
{
    int z;
    enum State { SOLID, LIQUID, GAS, PLASMA } state;
} oxygen = { 8, GAS };
 
// type enum State and its enumeration constants stay visible here, e.g.
void foo(void)
{
    enum State e = LIQUID; // OK
    printf("%d %d %d ", e, oxygen.state, PLASMA); // prints 1 2 3
}

Пример

#include <stdio.h>
 
int main(void)
{
    enum TV { FOX = 11, CNN = 25, ESPN = 15, HBO = 22, MAX = 30, NBC = 32 };
 
    printf("List of cable stations:\n");
    printf(" FOX: \t%2d\n", FOX);
    printf(" HBO: \t%2d\n", HBO);
    printf(" MAX: \t%2d\n", MAX);
}

Вывод:

List of cable stations:
 FOX:   11
 HBO:   22
 MAX:   30

Ссылки

  • Стандарт C23 (ISO/IEC 9899:2023):
    • 6.2.5/21 Типы (с. 39)
    • 6.7.2.2 Спецификаторы перечислений (с. 107-112)
  • Стандарт C17 (ISO/IEC 9899:2018):
    • 6.2.5/16 Типы (с. 32)
    • 6.7.2.2 Спецификаторы перечислений (с. 84-85)
  • Стандарт C11 (ISO/IEC 9899:2011):
    • 6.2.5/16 Типы (с. 41)
    • 6.7.2.2 Спецификаторы перечислений (с. 117-118)
  • Стандарт C99 (ISO/IEC 9899:1999):
    • 6.2.5/16 Типы (с. 35)
    • 6.7.2.2 Спецификаторы перечислений (с. 105-106)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
    • 3.1.2.5 Типы
    • 3.5.2.2 Спецификаторы перечислений
END_OF_DOCUMENT_MARKER

Ключевые слова

enum

См. также

Документация C++ по объявлению перечислений

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/enum

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API