Как определить перечислимый тип (enum) в C?

252

Я не уверен, что такое правильный синтаксис для использования C-перечислений. У меня есть следующий код:

enum {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy = IMMEDIATE;

Но это не скомпилируется со следующей ошибкой:

error: conflicting types for ‘strategy’
error: previous declaration of ‘strategy’ was here

Что я делаю неправильно?

  • 6
    Летний вопрос, наверное, никто этого не увидит; но почему это дает ошибку? Насколько мне известно, это должно работать на отлично, как и в вопросе.
  • 0
    @ThoAppelsin - Некромирующий некро здесь, но здесь он идет - Проверьте Йоханнеса Шауба - ответ Литба. Синтаксис неправильный, имя перечисления (стратегия) идет перед значениями перечисления (случайное, немедленное, поиск).
Показать ещё 7 комментариев
Теги:
enums

12 ответов

357
Лучший ответ

Объявление переменной enum выполняется следующим образом:

enum strategy {RANDOM, IMMEDIATE, SEARCH};
enum strategy my_strategy = IMMEDIATE;

Однако вы можете использовать typedef, чтобы сократить объявления переменных, например:

typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy my_strategy = IMMEDIATE;

Наличие соглашения об именах для различения типов и переменных является хорошей идеей:

typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy_type;
strategy_type my_strategy = IMMEDIATE;
  • 0
    Но OP хотел переменную анонимного типа enum
  • 0
    Почему это принятый ответ?
Показать ещё 1 комментарий
462

Стоит отметить, что вам не нужен typedef. Вы можете просто сделать это следующим образом

enum strategy { RANDOM, IMMEDIATE, SEARCH };
enum strategy my_strategy = IMMEDIATE;

Это вопрос стиля, предпочитаете ли вы typedef. Без него, если вы хотите обратиться к типу перечисления, вам нужно использовать enum strategy. С его помощью вы можете просто сказать strategy.

Оба способа имеют свои про и минусы. Один из них более многословен, но сохраняет идентификаторы типов в пространстве имен тегов, где они не будут конфликтовать с обычными идентификаторами (подумайте о struct stat и функции stat: они также не конфликтуют), и где вы сразу видите что это тип. Другой - короче, но привносит идентификаторы типов в обычное пространство имен.

  • 6
    Это не должен быть принятый ответ, потому что это неправильно. Вы не можете использовать стратегию enum {...}; в C - вы можете и должны делать это в C ++, хотя.
  • 19
    @Clearer: этот код работает отлично. Вот рабочий пример: ideone.com/T0YV17 Обратите внимание, что в обеих строках используется ключевое слово enum .
Показать ещё 5 комментариев
51

Вы пытаетесь объявить strategy дважды, и почему вы получаете указанную выше ошибку. Следующие работы без каких-либо жалоб (скомпилированы с gcc -ansi -pendantic -Wall):

#include <stdio.h>

enum { RANDOM, IMMEDIATE, SEARCH } strategy = IMMEDIATE;

int main(int argc, char** argv){
    printf("strategy: %d\n", strategy);

    return 0;
}

Если вместо вышесказанного вторая строка была изменена на:

...
enum { RANDOM, IMMEDIATE, SEARCH } strategy;
strategy = IMMEDIATE;
...

Из предупреждений вы можете легко увидеть свою ошибку:

enums.c:5:1: warning: data definition has no type or storage class [enabled by default]
enums.c:5:1: warning: type defaults to ‘int’ in declaration of ‘strategy’ [-Wimplicit-int]
enums.c:5:1: error: conflicting types for ‘strategy’
enums.c:4:36: note: previous declaration of ‘strategy’ was here

Таким образом, компилятор принял strategy = IMMEDIATE для объявления переменной с именем strategy с типом по умолчанию int, но уже было объявление объявления с этим именем.

Однако, если вы поместили назначение в функцию main(), это будет действительный код:

#include <stdio.h>

enum { RANDOM, IMMEDIATE, SEARCH } strategy = IMMEDIATE;

int main(int argc, char** argv){
    strategy=SEARCH;
    printf("strategy: %d\n", strategy);

    return 0;
}
  • 19
    +1 за объяснение исходной ошибки.
47

Когда вы говорите

enum {RANDOM, IMMEDIATE, SEARCH} strategy;

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

typedef enum {RANDOM, IMMEDIATE, SEARCH} StrategyType; 
StrategyType strategy = IMMEDIATE;
  • 9
    Почему это не полезно? Если меня не волнует название типа, зачем мне его давать? Единственное, что здесь было задумано, - это присвоить имя переменной, чтобы можно было присвоить ей новые значения.
  • 3
    Я сказал, что это не ОЧЕНЬ полезно, и я не верю, что это так. Конечно, я не использую этот шаблон в своем собственном коде. YMMV.
Показать ещё 4 комментария
13

Как написано, в коде нет ничего плохого. Вы уверены, что не сделали что-то вроде

int strategy;
...
enum {RANDOM, IMMEDIATE, SEARCH} strategy;

В каких строках указывают сообщения об ошибках? Когда он говорит, что "предыдущее объявление" стратегии "было здесь", что "здесь" и что оно показывает?

  • 6
    Он, вероятно, сделал strategy = IMMEDIATE; в области видимости файла. Назначение не может происходить в области видимости файла вне всех функций. Таким образом, компилятор попытался сделать все возможное из ошибки и предположил, что он имел в виду int strategy = IMMEDIATE; В этот момент произошел конфликт.
  • 0
    Ах, хорошая мысль. Не думал об этом.
Показать ещё 2 комментария
11

@ThoAppelsin в своем комментарии к опубликованному вопросу прав. Фрагмент кода, отправленный в вопросе, действителен и без ошибок. Ошибка, которую вы имеете, должна быть связана с другим плохим синтаксисом в любом другом месте вашего исходного файла c. enum{a,b,c}; определяет три символьные константы (a, b и c), которые являются целыми числами со значениями 0, 1 и 2 соответственно, но когда мы используем enum, это происходит потому, что мы надеваем Обычно меня интересует конкретное целочисленное значение, мы больше заботимся о значении символьного имени константы. Это означает, что вы можете это сделать:

#include <stdio.h>
enum {a,b,c};
int main(){
  printf("%d\n",b);
  return 0;
}

и это выведет 1.

Это также будет справедливо:

#include <stdio.h>
enum {a,b,c};
int bb=b;
int main(){
  printf("%d\n",bb);
  return 0;
}

и будет выводить то же, что и раньше.

Если вы это сделаете:

enum {a,b,c};
enum {a,b,c};

у вас будет ошибка, но если вы это сделаете:

enum alfa{a,b,c};
enum alfa;

у вас не будет никаких ошибок.

вы можете сделать это:

enum {a,b,c};
int aa=a;

и aa будет целочисленной переменной со значением 0. но вы также можете это сделать:

enum {a,b,c} aa= a;

и будет иметь тот же эффект (т.е. aa является int с 0 значением).

вы также можете сделать это:

enum {a,b,c} aa= a;
aa= 7;

и aa будет int со значением 7.

потому что вы не можете повторить определение символической константы с использованием enum, как я уже говорил ранее, вы должны использовать теги, если хотите объявить int vars с помощью enum:

enum tag1 {a,b,c};
enum tag1 var1= a;
enum tag1 var2= b;

использование typedef позволяет безопасно записывать каждый раз enum tag1 для определения переменной. С помощью typedef вы можете просто ввести Tag1:

typedef enum {a,b,c} Tag1;
Tag1 var1= a;
Tag1 var2= b;

Вы также можете:

typedef enum tag1{a,b,c}Tag1;
Tag1 var1= a;
enum tag1 var2= b;

Последнее, что сказать, что, поскольку мы говорим об определенных символьных константах, лучше использовать заглавные буквы при использовании enum, то есть, например:

enum {A,B,C};

вместо

enum {A,B,C};
10

Стоит отметить, что в С++ вы можете использовать "enum" для определения нового типа без инструкции typedef.

enum Strategy {RANDOM, IMMEDIATE, SEARCH};
...
Strategy myStrategy = IMMEDIATE;

Я считаю этот подход более дружелюбным.

[edit - уточнил статус С++ - у меня это было изначально, а затем удалено!]

  • 0
    Да, вы никогда не должны использовать typedef с перечислениями (или структурами, объединениями и т. Д.) В C ++.
  • 17
    Этот вопрос для C, а не для C ++. В C приведенный выше код недействителен - вы должны либо использовать typedef , либо указать enum в объявлении переменной: enum Strategy {RANDOM, IMMEDIATE, SEARCH}; ... enum Strategy myStrategy = НЕМЕДЛЕННАЯ;
Показать ещё 2 комментария
6

Кажется, что есть замешательство в декларации.

Когда strategy предшествует {RANDOM, IMMEDIATE, SEARCH}, как показано ниже,

enum strategy {RANDOM, IMMEDIATE, SEARCH};

вы создаете новый тип с именем enum strategy. Однако при объявлении переменной вам нужно использовать enum strategy. Вы не можете просто использовать strategy. Таким образом, следующее недопустимо.

enum strategy {RANDOM, IMMEDIATE, SEARCH};
strategy a;

В то время как справедливо следующее:

enum strategy {RANDOM, IMMEDIATE, SEARCH};

enum strategy queen = RANDOM;
enum strategy king = SEARCH;
enum strategy pawn[100];

Когда strategy появляется после {RANDOM, IMMEDIATE, SEARCH}, вы создаете анонимное перечисление, а затем объявляете strategy переменной такого типа.

Итак, теперь вы можете сделать что-то вроде

enum {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy = RANDOM;

Однако вы не можете объявить какую-либо другую переменную типа enum {RANDOM, IMMEDIATE, SEARCH}, потому что вы ее никогда не называли. Поэтому недопустимо следующее:

enum {RANDOM, IMMEDIATE, SEARCH} strategy;
enum strategy a = RANDOM;

Вы также можете комбинировать оба определения

enum strategy {RANDOM, IMMEDIATE, SEARCH} a, b;

a = RANDOM;
b = SEARCH;
enum strategy c = IMMEDIATE;

Typedef, как указано выше, используется для создания более короткого объявления переменной.

typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy;

Теперь вы сказали компилятору, что enum {RANDOM, IMMEDIATE, SEARCH} является автономным с strategy. Итак, теперь вы можете свободно использовать strategy как тип переменной. Вам больше не нужно набирать enum strategy. В настоящее время действует

strategy x = RANDOM;

Вы также можете комбинировать Typedef вместе с именем enum, чтобы получить

typedef enum strategyName {RANDOM, IMMEDIATE, SEARCH} strategy;

Не так много преимуществ использования этого метода, кроме того, что вы можете теперь использовать strategy и enum strategyName взаимозаменяемые.

typedef enum strategyName {RANDOM, IMMEDIATE, SEARCH} strategy;

enum strategyName a = RANDOM;
strategy b = SEARCH;
  • 0
    Отличный ответ. Я также сталкивался с определениями перечисления, написанными так: typedef enum strategy {RANDOM, IMMEDIATE, SEARCH} strategy или typedef enum strategy {RANDOM, IMMEDIATE, SEARCH} strategy_type . Имеет ли это какое-либо преимущество перед typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy ? Не могли бы вы добавить их в свой ответ для полноты?
  • 0
    Да. Я изменил свой ответ. Насколько мне известно, в общем случае нет никаких существенных преимуществ.
Показать ещё 1 комментарий
2

Если вы объявите имя для перечисления, ошибка не будет.

Если не объявлено, вы должны использовать typedef:

enum enum_name {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy = IMMEDIATE;

Не будет отображаться ошибка...

1

Моя любимая и единственная использованная конструкция всегда была:

typedef enum MyBestEnum
{
    /* good enough */
    GOOD = 0,
    /* even better */
    BETTER,
    /* divine */
    BEST
};

Я верю, что это устранит вашу проблему.

1

Тарк ответ самый лучший.

Большая часть обсуждения enum - красная сельдь.

Сравните этот фрагмент кода: -

int strategy;
strategy = 1;   
void some_function(void) 
{
}

который дает

error C2501: 'strategy' : missing storage-class or type specifiers
error C2086: 'strategy' : redefinition

с этим, который компилируется без проблем.

int strategy;
void some_function(void) 
{
    strategy = 1;   
}

strategy переменных должна быть установлена при объявлении или внутри функции и т.д. Вы не можете писать произвольное программное обеспечение - в частности, назначения - в глобальной области видимости.

Тот факт, что он использовал enum {RANDOM, IMMEDIATE, SEARCH} вместо int, имеет отношение только к той степени, в которой он запутал людей, которые не могут видеть за его пределами. Сообщения об ошибках переопределения в вопросе показывают, что автор поступил неправильно.

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

Пример 1. НЕПРАВИЛЬНО!

enum {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy = IMMEDIATE;
void some_function(void) 
{
}

Пример 2. ПРАВО.

enum {RANDOM, IMMEDIATE, SEARCH} strategy = IMMEDIATE;
void some_function(void) 
{
}

Пример 3. ПРАВО.

enum {RANDOM, IMMEDIATE, SEARCH} strategy;
void some_function(void) 
{
    strategy = IMMEDIATE;
}

Пример 4. ПРАВО.

void some_function(void) 
{
    enum {RANDOM, IMMEDIATE, SEARCH} strategy;
    strategy = IMMEDIATE;
}

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

0

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

typedef enum state {a = 0, b = 1, c = 2} состояние;

typedef enum state {a = 0, b = 1, c = 2} state;

typedef enum state old; // New type, alias of the state type.
typedef enum state new; // New type, alias of the state type.

new now     = a;
old before  = b;

printf("State   now = %d \n", now);
printf("Sate before = %d \n\n", before);
  • 0
    new - плохой выбор идентификаторов в семействе C, потому что это оператор в C ++.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню