Тем не менее, есть шанс, что GCC предлагает какое-то расширение компилятору C, которое позволяет это. Поиск необходим.

е, что gcc не выдает предупреждение с помощью следующего кода. Как я могу заставить его сделать предупреждение?

typedef enum
{
    REG8_A,
    REG8_B,
    REG8_C
}REG8;

typedef enum
{
    REG16_A,
    REG16_B,
    REG16_C
}REG16;

void function(REG8 reg8)
{

}

int main(void)
{
    function(REG16_A);    // Should warn about wrong enum
}
 ulidtko17 янв. 2011 г., 13:49
Какая у вас версия GCC? GCC 4.4.5, установленный на моей машине, отклоняет код с соответствующим сообщением об ошибке. Смотри мой ответ:stackoverflow.com/questions/4669454/...
 NickHalden22 дек. 2012 г., 20:02
@ RocketMagnet Мне было интересно, что вы в конечном итоге использовали в качестве решения этой проблемы. Я все еще вижу несколько проблем с принятым решением.
 Rocketmagnet17 янв. 2011 г., 14:27
Версия 3.4.4. И, к сожалению, нет возможности изменить это.
 Rocketmagnet24 дек. 2012 г., 17:50
@JGord - К сожалению, я никогда не нашел решения.

Ответы на вопрос(6)

-Wenum-compare (который включен по умолчанию, если вы включите-Wall), вы должны выполнить сравнение константы перечисления, прежде чем передать ее функции, чтобы получить желаемую диагностику.

-Wenum-сравнить

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

http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

Поскольку такое сравнение происходит автоматически, когда мы вызываем функцию, мы можем обернуть функцию в макрос. Для удобства чтения я также определяю макрос SAFE_ENUM, который выполняет безвредное сравнение константы перечисления (это то, что в конечном итоге выдает предупреждение при попытке передать неверную константу перечисления вfoo или жеbar).

/**
  SAFE_ENUM: evaluate an enumeration constant safely
  TYPE: the enumeration type
  VAL: the enumeration constant to evaluate
*/
#define SAFE_ENUM(TYPE, VAL) ((VAL) == (TYPE)0 ? (VAL) : (VAL))

typedef enum
{
    REG8_DEFAULT,
    REG8_A,
    REG8_B,
    REG8_C
} Reg8;

typedef enum
{
    REG16_DEFAULT,
    REG16_A,
    REG16_B,
    REG16_C
} Reg16;

void foo(Reg8 reg8)
#define foo(reg8) foo(SAFE_ENUM(Reg8, reg8))
{
    printf("%s called with value %d\n", __func__, reg8);
}

void bar(Reg16 reg16)
#define bar(reg16) bar(SAFE_ENUM(Reg16, reg16))
{
    printf("%s called with value %d\n", __func__, reg16);
}

int main(void)
{
    foo(REG8_A);  // ok
    bar(REG16_A); // ok
    foo(REG16_B); // warning
    bar(REG8_B);  // warning

    Reg16 a_reg16 = 42;
    foo(a_reg16); // warning: foo requires a Reg8 but you gave it a Reg16
}
 Étienne05 нояб. 2014 г., 18:19
+1, потому что это хорошая идея, к сожалению, она не работает при использовании с переменными перечисления, это скомпилируется без предупреждения:Reg16 reg = 42; bar(reg);
 Étienne06 нояб. 2014 г., 00:01
Я имел в виду, что ваше решение прекрасно отвечает на вопрос и, вероятно, лучшее, что можно получить в C, но, к сожалению, enum все еще не совсем безопасен, как следует из названия макроса, по крайней мере, он все еще менее безопасен, чем, например, перечисление C ++ , Можно, например, делатьReg16 reg = REG8_A; bar(reg);.
 Brandin05 нояб. 2014 г., 23:05
@ Этьен Спасибо за комментарий. Однако по моим тестам переменные работают нормально, то есть bar (reg) должен быть в порядке в соответствии с примером. bar хочет Reg16, и вы дали ему точно Reg16, когда вызываете bar (reg). Попробуйте foo (reg), и он выдаст предупреждение, потому что reg - это Reg16, но foo хочет Reg8.

что вы готовы передавать указатели, а не голые перечисления, например,

typedef enum
{
    REG8_A,
    REG8_B,
    REG8_C
} REG8;

typedef enum
{
    REG16_A,
    REG16_B,
    REG16_C
} REG16;

void function(REG8 * reg8)
{

}

int main(void)
{
    REG16 r = REG16_A;
    function(&r);
    return 0;
}

Не совсем элегантное решение, но оно дает предупреждение, по крайней мере, сgcc -Wall:

$ gcc -Wall warn_enum.c -o warn_enum
warn_enum.c: In function ‘main’:
warn_enum.c:23: warning: passing argument 1 of ‘function’ from incompatible pointer type
$
 Rocketmagnet17 янв. 2011 г., 17:03
Да. -Wall и -Wextra
 Paul R17 янв. 2011 г., 23:07
Почему анонимный понижатель?
 Paul R17 янв. 2011 г., 17:36
@Rocketmagent: ОК. Из другого комментария я вижу, что вы используете очень старую версию gcc, что может объяснить, почему вы не видите предупреждения. gcc 4.0 и более поздних версий должен выдавать вышеуказанное предупреждение
 Paul R17 янв. 2011 г., 15:37
@Rocketmagnet: вы собирали с-Wall ? (см. выше)
 Rocketmagnet17 янв. 2011 г., 15:21
Я попробовал это, но это тоже не выдало предупреждения.

должен использование-Wconversion а также-Werror варианты, чтобы предотвратить любые неявные преобразования типов. Это дает ошибку с кодом, размещенным Полом Р. Но оригинальный код все равно прекрасно компилируется. Я не знаю почему.

 Gp2mv319 апр. 2017 г., 11:47
-Wconversion дает много других бесполезных предупреждений. Это слишком ограничительно ...

C не различает перечислимый тип и базовый целочисленный тип. (Некоторые компиляторы могут включать проверку типов дляenumс илиtypedefs как расширения; YMMV.)

Чтобы получить проверку типа в C, вы можете использоватьstructс, но тогда вы теряете использование встроенных операторов сравнения и возможностьswitch на переменную. Вы можете попробовать что-то вроде этого, хотя:

typedef struct {
    enum {
        reg8_val_A,
        reg8_val_B,
        reg8_val_C,
    } val;
} reg8;
#define reg8_A (reg8){.val = reg8_val_A}
#define reg8_B (reg8){.val = reg8_val_B}
#define reg8_C (reg8){.val = reg8_val_C}
…
bool
is_A_or_B(reg8 reg) {
    if reg.val == reg8_A.val    // one way to compare
        return true;
    switch (reg.val) {
        case reg8_val_B:        // the other way to compare; note that
            return true;        // “case reg8_B.val:” will *not* work
        case reg8_val_C:
            return false;
        default:
            fprintf(stderr, "bad reg value %d\n", reg.val);
            abort();
    }
}

(Использует некоторые функции C99.)

Решение Вопроса

что вы используете компилятор C, а не C ++. А такжев С Типы enum на самом деле не являются типами, перечисления в C просто содержат константы типа int, и они могут свободно смешиваться с любыми целыми числами и любой арифметикой.

В C ++ вместо этого у вас естьреальные перечисления как вы хотели бы думать о них, и необходимая проверка типов происходит в соответствии с языковым стандартом.

Ваша проблема может быть решена двумя способами:

Используйте компилятор C ++.

Таким образом, вы будете иметьреальные перечисления, как вы хотите их.

Измените ваш код на стиль чисто C, то есть не используйте перечисления, так как в C это просто наборы констант, где компилятор только помогает вам упорядочивать значения констант. И в твы будет ответственным за согласованность «типов» переданных констант. Еще раз: для C члены enum являются просто константами типа int, вы не можете сделать их типизированными.

#define REG8_A 0
#define REG8_B 1
#define REG8_C 2

#define REG16_A 0
#define REG16_B 1
#define REG16_C 2
 rockdaboot05 июн. 2015 г., 15:13
gcc не выводит все предупреждения, которые должен делать компилятор C На Bugs @ GCC они сказали мне, что разработчики должны заботиться о других вещах. Звучит так, как будто у них недостаточно власти. clang 3.5 выводит предупреждения, например: warning: неявное преобразование из типа перечисления 'blu_t' в другой тип перечисления 'bla_t' [-Wenum-преобразование]
 Jonny14 янв. 2014 г., 03:28
Есть та же проблема с ObjC здесь. Я думаю, что это работает так же, как C здесь. Использование Apple LLVM 5.0.
 Rocketmagnet17 янв. 2011 г., 14:44
Интересная идея.
 Rocketmagnet17 янв. 2011 г., 14:21
я мог былюбовь использовать C ++ вместо C. Но это не вариант здесь, к сожалению. Но я думаю, что я буду продолжать использовать перечисления, потому что по крайней мере это будет более понятно при чтении кода.
 ulidtko17 янв. 2011 г., 14:26
Вы можете попробовать пометитьREGn_ "типы" с некоторым старшим битом. Например,enum REG8 { REG8_A=0x80, REG8_B, REG8_C}; и сделать биты разными для разных перечислений. Таким образом, вы можете добавить проверки во время выполнения (утверждения) черезvalue & 0x80 к вашим функциям, которые могут «проверить тип».
$ g++ test3.cpp -o test3
test3.cpp: In function ‘int main()’:
test3.cpp:22: error: cannot convert ‘REG16’ to ‘REG8’ for argument ‘1’ to ‘void function(REG8)’
 swegi17 янв. 2011 г., 13:55
это g ++, а не gcc.
 ulidtko17 янв. 2011 г., 14:13
Тем не менее, есть шанс, что GCC предлагает какое-то расширение компилятору C, которое позволяет это. Поиск необходим.
 Rocketmagnet17 янв. 2011 г., 14:04
К сожалению, я не могу скомпилировать его как C ++, он должен быть скомпилирован как C.
 ulidtko17 янв. 2011 г., 13:55
g̶c̶c̶ ̶p̶r̶o̶d̶u̶c̶e̶s̶ ̶t̶h̶e̶ ̶s̶a̶m̶e̶ ̶m̶e̶s̶s̶a̶g̶e̶.̶ Когда я переименуюtest3.cpp вtest3.cда, он компилируется без предупреждения.

Ваш ответ на вопрос