Почему возникает ошибка при прямом сравнении двух перечислений?

У меня есть код, который я переношу на новую платформу, и он начал давать мне ошибку в сравнении двух счетчиков из двух разных списков перечислителей. Я смущен, почему это дает мне ошибку об этом.

Раздел спецификаторов перечислений в спецификации C (6.7.2.2) гласит:

Идентификаторы в списке перечислителей объявляются как константы, которые имеют тип int и могут появляться везде, где это разрешено. 127) Перечислитель с = определяет его константа перечисления как значение постоянного выражения. Если первый счетчик no =, значение его константы перечисления равно 0.

Итак, я должен иметь возможность использовать элементы перечисления так же, как и int-константы. В этой небольшой примерной программе:

enum first {
  a,
  b
};

enum second {
 c,
 d
};

int main(){
    enum first myf = a;
    enum second mys = c;

    if(myf == mys)
        printf("same value\n"); 
    return 0;
}

Когда скомпилировано с gcc -Wall -Werror, я получаю сообщение:

error: сравнение между 'enum first и' enum second [-Werror = enum-compare]

Я знаю, что если я привожу как myf, так и mys как int, то компилятор будет счастлив, так же как я могу установить пару int со значениями из myf и mys и сделать сравнение; но почему я должен сделать это, чтобы избавиться от предупреждения? Почему это предупреждение существует в первую очередь? В этом должна быть какая-то опасность, которую я не вижу.


ПРИМЕЧАНИЕ.. Я прочитал документацию gcc по этому флагу перечислимого числа, но он ничего не говорит:

-Wenum-сравнить
Предупредите о сравнении значений различных перечисленных типов. В С++ перечислены также нечеткие совпадения в условных выражениях, и предупреждение включено по умолчанию. В C это предупреждение включено -Wall.

Ответ 1

Это не предупреждение из-за проблемы соответствия стандартам, это одно из предупреждений о том, что это "не кажется правильным". Если вы думаете о типичном использовании перечислений, такое сравнение не имеет большого смысла во многих случаях. Например:

enum Day {
  Sunday,
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday
};

enum Month {
  January,
  February,
  March,
  April,
  May,
  June,
  July,
  August,
  September,
  October,
  November,
  December
};

enum Day day = Wednesday;
enum Month month = April; 

if (day == month) { ... }

Это оценивается как true, но в целом сравнение не имеет большого смысла. Если вы знаете, что это имело это в виду, то, как вы отметили, приведённый код убедит компилятор.

Ответ 2

Это предупреждение, потому что у вас есть предупреждающий флаг. Описание флага не объясняет, почему оно существует, но, вероятно, можно предположить, что оно существует для предотвращения случайного сравнения между различными типами перечислений, поскольку это обычно является ошибкой.

Кроме того, вы правы, что вы можете использовать значения перечисления так же, как и int-константы. И если вы сказали if (myf == c), то он, скорее всего, не бросил бы предупреждение (я говорю, скорее всего, потому, что я не экспериментировал, и GCC честно может делать все, что захочет, с этим предупреждением, но технически c - это просто интегральная постоянная и не несет тип enum second). Но вместо этого вы явно сравниваете два значения разных типов перечисления.

Ответ 4

if((int)myf == (int)mys)

Это должно сделать это. Но это грязная практика, используйте ее только в том случае, если обе перечисления имеют разные "версии" одной и той же группы, такие как новые, в конце будут содержать новые ключевые слова.