Ответ 1
Это объявление:
enum fruit {
apple,
orange
};
объявляет три вещи: тип, называемый enum fruit
, и два счетчика, называемых apple
и orange
.
enum fruit
на самом деле является отдельным типом. Он совместим с целым типом, определенным для реализации; например, enum fruit
может быть совместимо с int
, с char
или даже с unsigned long long
, если реализация выбирает, пока выбранный тип может представлять все значения.
Перечислители, с другой стороны, являются константами типа int
. На самом деле существует общий прием использования объявленного enum
объявления для объявления констант int
без использования препроцессора:
enum { MAX = 1000 };
Да, это означает, что константа apple
, даже если она была объявлена как часть определения enum fruit
, на самом деле не имеет типа enum fruit
. Причины этого исторические. И да, вероятно, было бы больше смысла для счетчиков быть константами типа.
На практике это несоответствие редко имеет значение. В большинстве случаев дискретные типы (т.е. Целые и перечисляемые типы) в значительной степени взаимозаменяемы, и неявные преобразования обычно делают правильные вещи.
enum fruit { apple, orange };
enum fruit obj; /* obj is of type enum fruit */
obj = orange; /* orange is of type int; it's
implicitly converted to enum fruit */
if (obj == orange) { /* operands are converted to a common type */
/* ... */
}
Но результат состоит в том, что, как вы видели, компилятор вряд ли предупредит вас, если вы используете константу, связанную с одним перечислимым типом, когда вы хотите использовать другую.
Один из способов получить сильную проверку типов - это обернуть ваши данные в структуру:
enum fruit { /* ... */ };
enum color { /* ... */ };
struct fruit { enum fruit f; };
struct color { enum color c; };
struct fruit
и struct color
являются четкими и несовместимыми типами без имплицитного (или явного) преобразования между ними. Недостатком является то, что вы должны явно ссылаться на элемент .f
или .c
. (Большинство программистов на C просто рассчитывают на то, что они смогут правильно разобраться - со смешанными результатами.)
(typedef
не дает вам надежной проверки типа, несмотря на имя, он создает псевдоним для существующего типа, а не новый тип.)
(Правила в С++ немного отличаются.)