Является ли это перечисление enum стандартным?

Таким образом, обычно перечисление предназначено для объявления группы "постоянных целых чисел" как другого типа, который представляет что-то. Например.

enum Color {RED=0, BLUE, YELLOW};

Это ясно. Но недавно я встретил в коде код. Это было в компиляторе для встроенных систем.

enum State {DISABLED=0, ENABLED=!DISABLED};

И это сработало отлично. Он вел себя как булевский тип. Мой вопрос: если он (этот синтаксис) совместим с ANSI?

Если это стандартное соответствие, то почему компиляторы определяли внутренне что-то вроде _Bool для логического представления, а затем в stdbool.h (для языка C):

#define bool _Bool
... // here goes definitions of true and false

вместо

enum bool {false=0, true=!false};

Что намного чище?

Ответ 1

Да, объявление абсолютно корректно и переносимо как в C, так и в С++.

В обоих C и С++ это:

enum State {DISABLED=0, ENABLED=!DISABLED};

в точности эквивалентно этому:

enum State {DISABLED=0, ENABLED=1};

и к этому:

enum State {DISABLED, ENABLED};

но по разным причинам.

В C унарный оператор ! дает результат типа int со значением либо 0 (если операнд не равен 0) или 1 (если операнд равен 0). !x эквивалентно x == 0. (Любое ненулевое значение считается истинным при использовании в качестве условия, но операторы ! и ==, среди прочих, всегда дают результат точно 0 или 1.) Константы перечисления всегда имеют тип int; если задано значение, оно при необходимости преобразуется в int.

(C добавил тип _Bool в стандарте 1999 года, но все операторы, которые дают логически "логические" значения, все еще дают результаты типа int.)

В С++ результат унарного оператора ! имеет тип bool. Результат: false или true, где оператор C ! дал бы 0 или 1 соответственно. Как и в C, если задано значение, оно преобразуется по мере необходимости; значения bool false и true преобразуются в 0 и 1 соответственно.

В C константы перечисления всегда имеют тип int. В С++ они относятся к типу перечисления, в этом случае enum State.

Ссылаясь на более раннюю константу перечисления в одном объявлении типа, является законным. Каждая константа перечисления становится видимой после объявления.

Что-то вроде:

enum bool { false = 0, true = !false );

становится более четким, чем

enum bool { false = 0, true = 1 };

(в C, это было бы незаконно в С++), я почтительно не согласен. Константа 1 совершенно понятна любому, кто знаком с C. Переписывание его как !false не помогает. Фактически, когда <stdbool.h> недоступен (что-то редкое в наши дни), я использовал:

typedef enum { false, true } bool;

Тот факт, что false и true будут заданы их правильные значения, является IMHO достаточно очевидным.

Что касается того, почему C99 не использовал определение enum, как это, я подозреваю, потому что каждый тип перечисления совместим с некоторым целым числом, определенным для реализации. (Для gcc обычно это unsigned int или int.) Комитет хотел, чтобы _Bool был отдельным типом с рангом преобразования ниже любого другого целочисленного типа. (И они не могли сделать bool ключевое слово без нарушения существующего кода.)

Ответ 2

Да, это стандартно.

!DISABLED - это действительное константное выражение, которое является всем, что требуется для значения enum.

enum State {DISABLED=0, ENABLED= (!DISABLED)};
//                               ^^^^^^^^^^^

В момент ссылки на DISABLED компилятор знает свое значение, поэтому он может вычислить значение полученного из него выражения, то есть !DISABLED. Это причудливый способ написания ENABLED=1.

Ответ 3

В соответствии со стандартом C (6.2.1 Области идентификаторов)

Каждая константа перечисления имеет область, которая начинается сразу после появление его определяющего перечислителя в списке перечислителей

То же самое верно в С++ (3.3.2 Точка декларации)

5 Точка объявления для перечислителя сразу после enumerator-definition. [Пример:

const int x = 12;
{ enum { x = x }; }

Здесь перечислитель x инициализируется значением константы x, а именно 12. -end example]

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

Что касается типа C _Bool, то он появился в C 99. До этого стандарта используются либо манифестные константы, либо перечисления в C.

Нет смысла определять нумерацию, подобную этой

enum bool {false=0, true!=false};

потому что тип _Bool уже имеет два значения 0 и 1.