Какой смысл разрешать идентификатор для перечисления?
Почему компилятор не жалуется, когда я пытаюсь назначить неверные значения переменной a
типа enum answer
?
#include <stdio.h>
int main()
{
enum answer {NO, YES};
enum gender {MALE, FEMALE};
enum answer a = 5; /* Assign an invalid value. */
printf("answer: %d\n", a);
a = MALE; /* Assign a value of wrong type */
printf("answer: %d\n", a);
return 0;
}
Вот результат:
$ gcc -std=c99 -pedantic -Wall -Wextra enum.c
$ ./a.out
answer: 5
answer: 0
Если enum
не приводит к проверке типов, то в чем смысл синтаксиса:
enum [identifier] {enumerator-list}
Я использовал answer
и gender
как идентификатор моего перечисления. Какой смысл разрешать этот синтаксис?
Я имею в виду, что этот код может быть очень хорошо написан как
enum {NO, YES};
enum {MALE, FEMALE};
В чем смысл этого синтаксиса?
enum answer {NO, YES};
enum gender {MALE, FEMALE};
Ответы
Ответ 1
Почему компилятор не жалуется, когда я пытаюсь назначить неверные значения переменной a
типа enum answer
?
Так как в C an enum
практически эквивалентен int
. Это было стандартизировано, как и это, и просто слишком много программ полагаются на это поведение, чтобы изменить его.
В С++ они разные типы, и компилятор жалуется:
$ g++ -Wall -Wextra a.c
a.c: In function 'int main()':
a.c:8:24: error: invalid conversion from 'int' to 'main()::answer' [-fpermissive]
a.c:11:14: error: cannot convert 'main()::gender' to 'main()::answer' in assignment
В чем смысл этого синтаксиса?
Мое быстрое предположение было бы совместимостью вперед.
Ответ 2
C предоставляет значения enumeration
непосредственно как integer, а в С++ enum
- реальный тип. Следовательно, в С++ enum
выполняется проверка типа , а в C перечисление только представляет константы типа int. Поэтому значения integer и enum могут быть перемешаны во всех арифметических операциях.
Ответ 3
Предполагая, что:
enum answer {NO, YES};
enum gender {MALE, FEMALE};
с:
enum answer bla = YES;
enum gender blop = MALE;
int bip = 0;
Хотя это не требуется стандартом C, он позволяет предупреждениям в следующих случаях:
bla = blop;
bip = bla;
Обратите внимание, что типы enum
являются арифметическими типами, и назначение между объектами разных арифметических типов всегда разрешено, но реализация по-прежнему может быть предупреждена. Как отмечалось в комментариях, правила с типами enum
отличаются для С++.
EDIT: еще один пример:
enum ans {
YES,
NO,
MAYBE
};
enum ans a = /* initializer */;
switch (a)
{
case YES:
break;
case NO:
break;
}
С -Wall
(то есть -Wswitch
), gcc
может предупредить, что:
tst.c: 15: 5: предупреждение: значение перечисления "MAYBE не обрабатывается в коммутаторе
Если у вас есть:
enum {
YES,
NO,
MAYBE
};
int a = /* initializer */;
gcc
не сможет предупредить. Так что фактически использование типа enum
вместо константы enum
помогает статическим анализаторам.