проверка типа enum в C / gcc - PullRequest
       20

проверка типа enum в C / gcc

18 голосов
/ 22 декабря 2011

См. Простой пример ниже.Когда функция, возвращающая один enum, назначается переменной с другим enum, я не получаю никаких предупреждений даже с gcc -Wall -pedantic.Почему компилятор C не может выполнить проверку типов на enum s?Или это gcc специфично?У меня нет сейчас доступа к любому другому компилятору, чтобы попробовать его.

enum fruit {
APPLE,
ORANGE
};

enum color {
RED,
GREEN
};

static inline enum color get_color() {
    return RED;
}

int main() {
    enum fruit ftype;
    ftype = get_color();
}

Ответы [ 6 ]

26 голосов
/ 22 декабря 2011

Это объявление:

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. (Большинство программистов на Си просто рассчитывают на то, что они смогут правильно все сделать - со смешанными результатами.)

(typedef не дает строгой проверки типа; несмотря на имя, он создает псевдоним для существующего типа, а не для нового типа.)

(правила в C ++ немного другие.)

5 голосов
/ 12 февраля 2015

Вероятно, большинство из нас понимают причины, лежащие в основе («спецификация говорит, что оно должно работать»), но мы также согласны, что это является причиной большого количества ошибок программирования на земле «C» и что обходной путь переноса структуры является грубым,Игнорирование проверок надстроек, таких как lint, вот что мы имеем:

3 голосов
/ 28 декабря 2011

gcc решил не предупреждать (как и clang), но icc (компилятор Intel) предупредит в этой ситуации. Если вам нужна дополнительная проверка типов для enum типов, вы можете передать свой код некоторому программному обеспечению для проверки статического кода, например Lint, которое может предупреждать в таких случаях.

gcc решил, что бесполезно предупреждать о неявных преобразованиях между типами enum, но также отметим, что C не требует от реализации выдачи диагностики в случае присваивания между двумя различными типами enum. Это то же самое, что и для присвоения между любым арифметическим типом: диагностика не требуется для C. Например, gcc также не будет предупреждать, если вы назначите long long для char или short для long.

2 голосов
/ 22 декабря 2011

Это потому, что enum в C - это просто группа уникальных целочисленных констант, которые избавляют вас от необходимости #define целой связки констант. Это не похоже на C ++, где создаваемые enum имеют определенный тип. Вот так и есть С.

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

1 голос
/ 22 декабря 2011

Перечисление в C в основном обрабатывается как целое число.Это просто лучший способ использовать константы.

  // this would work as well
  ftype = 1;

Также можно указать значения:

  enum color {
     RED=0,GREEN,BLUE
  } mycolor;

  mycolor = 1; // GREEN
0 голосов
/ 31 марта 2018

У ребят из gcc всегда есть причина не делать что-то.

Используйте clang с параметрами -Wenum-conversion -Wassign-enum.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...