Я просматриваю много кода, который выглядит так
typedef enum {
OPTION1
OPTION2
} option_t
...
void a_function(option_t option){
if (option == OPTION1){
...
} else if (option == OPTION2){
...
} else {
// report an error!
// can we ever get here?
}
}
Мой вопрос: нужно ли предложение else
, которое сообщает об ошибке? Мне кажется, что, поскольку option
имеет тип option_t
, перечисление, которое имеет только 2 возможности, для option
не должно быть никакого значения, кроме OPTION1
и OPTION2
, поэтому должно быть невозможно выполнение предложения else
. .
@Gerhardh знает компилятор? Кажется, что option
быть option_t
вместо int
должно предотвратить это?
enum
в основном просто определяет имена для постоянных значений. Он не указывает для них конкретный целочисленный тип (со знаком или без знака, короткий или длинный,...) и не устанавливает некоторые ограничения.
Касательно «Может ли enum typedef в C принимать значение, превышающее количество элементов в перечислении?»: это не тот вопрос, который вы хотите задать; enum foo { a = 12 }
имеет значение больше, чем количество его именованных членов.
Перечисления не очень важны для безопасности типов и, как правило, нарушаются типом дизайна (на сегодняшний день грядущий C23 изменит многие дефекты языка C). В вашем примере OPTION1
имеет тип int
, а option_t
имеет некоторый целочисленный тип, достаточно большой, чтобы соответствовать всем значениям в списке перечисления, не обязательно int
.
Мой вопрос в том, нужно ли предложение else, которое сообщает об ошибке?
Это то, что известно как «защитное программирование». Теоретически перечисление не должно иметь никаких других значений. На практике ничто не мешает вам присвоить ему любое целочисленное значение. Или в случае багов с повреждением памяти ничто не мешает багу изменить его на другое значение.
Так что это зависит от ваших требований. Для коммерческих / любительских / требований к ПК else
, вероятно, не требуется. Для связанного с безопасностью, критически важного или аналогичного программного обеспечения (например, соответствия MISRA C) требуется else
и надлежащая практика.
Пост по теме: Как создать безопасное перечисление типов?
Вместо этого я использую unums, если #define по одной причине. Отладчики отображают имена перечислений, что упрощает отладку.
В стандарте C это не указано явно, но каждый перечисляемый тип на самом деле является некоторым обычным целочисленным типом. Хотя C 2018 6.12.5 16 говорит: «… Каждое отдельное перечисление представляет собой отдельный перечисляемый тип», 6.7.2.2 4 говорит: «Каждый перечисляемый тип должен быть совместим с char
, целочисленным типом со знаком или целочисленным типом без знака. Выбор типа определяется реализацией, но он должен быть способен представлять значения всех членов перечисления…»
Ни в одном из них не ясно, какие значения могут быть представлены в перечисляемом типе или определено ли поведение для значений, не входящих в число именованных значений перечисления — утверждение, что два типа совместимы, не является утверждением, что все значения одного типа представимы. по другому типу.
Что помешает вызывающему абоненту передать
-1
или4711
вашей функции?