Как определить перечислимый тип (enum) в C? - PullRequest
259 голосов
/ 09 июля 2009

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

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

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

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

Что я делаю не так?

Ответы [ 12 ]

446 голосов
/ 09 июля 2009

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

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

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

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

362 голосов
/ 09 июля 2009

Объявление переменной 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;
56 голосов
/ 30 декабря 2013

Вы пытаетесь объявить 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;
}
48 голосов
/ 09 июля 2009

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

enum {RANDOM, IMMEDIATE, SEARCH} strategy;

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

typedef enum {RANDOM, IMMEDIATE, SEARCH} StrategyType; 
StrategyType strategy = IMMEDIATE;
13 голосов
/ 09 июля 2009

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

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

На какие строки указывают сообщения об ошибках? Когда говорится, что «предыдущая декларация« стратегии »была здесь», что это «здесь» и что это показывает?

11 голосов
/ 12 октября 2014

@ 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 переменные с использованием 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 голосов
/ 09 июля 2009

Стоит отметить, что в C ++ вы можете использовать «enum» для определения нового типа, не нуждаясь в выражении typedef.

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

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

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

7 голосов
/ 13 декабря 2016

Кажется, в заявлении есть путаница.

Когда 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;
2 голосов
/ 24 ноября 2017

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

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

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

2 голосов
/ 25 декабря 2013

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

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

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

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

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