Jak zdefiniować typ enumerated (enum) w C?

Nie jestem pewien, jaka jest właściwa składnia używania enum C. Mam następujący kod:

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

Ale to nie kompiluje się, z następującym błędem:

error: conflicting types for ‘strategy’
error: previous declaration of ‘strategy’ was here
Co robię źle?
 277
Author: Stéphane Gimenez, 2009-07-09

13 answers

Deklarowanie zmiennej enum odbywa się w następujący sposób:

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

Można jednak użyć typedef, aby skrócić deklaracje zmiennych, w następujący sposób:

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

Posiadanie konwencji nazewnictwa do rozróżniania typów i zmiennych jest dobrym pomysłem:

typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy_type;
strategy_type my_strategy = IMMEDIATE;
 387
Author: RichieHindle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-07 15:34:57

Warto zaznaczyć, że nie potrzebujesz a typedef. Możesz to zrobić w następujący sposób

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

To pytanie o styl, czy wolisz typedef. Bez niego, jeśli chcesz odwołać się do typu wyliczenia, musisz użyć enum strategy. Z nim, można po prostu powiedzieć strategy.

Oba sposoby mają swoje plusy i minusy. Ten jest bardziej wyrazisty, ale zachowuje identyfikatory typu w przestrzeni nazw znaczników, gdzie nie będą one sprzeczne ze zwykłymi identyfikatorami (pomyśl o struct stat i stat funkcja: te też nie kolidują), i gdzie od razu widać, że jest to typ. Drugi jest krótszy, ale wprowadza identyfikatory typu do zwykłej przestrzeni nazw.
 453
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-09 16:12:55

Próbujesz zadeklarować strategy dwa razy i dlatego otrzymujesz powyższy błąd. Poniższe prace bez żadnych reklamacji (zestawione z gcc -ansi -pedantic -Wall):

#include <stdio.h>

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

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

    return 0;
}

Jeśli zamiast powyższego, druga linia została zmieniona na:

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

Z ostrzeżeń łatwo widać swój błąd:

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

Więc kompilator wziął {[6] } za deklarację zmiennej o nazwie strategy z domyślnym typem int, ale była już poprzednia deklaracja zmiennej o tym nazwisko.

Jeśli jednak umieścisz przypisanie w funkcji main(), będzie to poprawny kod:

#include <stdio.h>

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

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

    return 0;
}
 59
Author: Tarc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-16 09:28:02

Kiedy mówisz

enum {RANDOM, IMMEDIATE, SEARCH} strategy;

Tworzysz pojedynczą zmienną instancji, zwaną 'strategy' bezimiennego enum. To nie jest bardzo przydatna rzecz do zrobienia - potrzebujesz typedef:

typedef enum {RANDOM, IMMEDIATE, SEARCH} StrategyType; 
StrategyType strategy = IMMEDIATE;
 50
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-09 08:34:23

Jak napisano, nie ma nic złego w Twoim kodzie. Czy na pewno nie zrobiłeś czegoś takiego jak

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

Na jakie linie wskazują komunikaty o błędach? Kiedy mówi "poprzednia deklaracja' strategii 'była tutaj", co jest "tutaj" i co pokazuje?

 12
Author: John Bode,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-09 15:38:16

Warto wspomnieć, że w C++ można użyć "enum" do zdefiniowania nowego typu bez konieczności użycia instrukcji typedef.

enum Strategy {RANDOM, IMMEDIATE, SEARCH};
...
Strategy myStrategy = IMMEDIATE;
Uważam to podejście za bardziej przyjazne.

[edytuj-poprawiłem C++ status-miałem to w oryginale, potem usunąłem!]

 11
Author: Roddy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-09 09:16:03

@ThoAppelsin w komentarzu do pytania zamieszczonego ma rację. Fragment kodu zamieszczony w pytaniu jest poprawny i bez błędów. Błąd, który masz, musi być ponieważ inna zła składnia w dowolnym innym miejscu pliku źródłowego c. enum{a,b,c}; definiuje trzy stałe symboliczne (a, b i c), które są liczbami całkowitymi o wartościach 0,1 i odpowiednio 2, Ale kiedy używamy enum to dlatego, że zwykle nie zależy nam na konkretnej wartości całkowitej, bardziej zależy nam na znaczeniu symboliczna stała nazwa. Oznacza to, że możesz mieć to:

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

I to wyjdzie 1.

To również będzie ważne:

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

I wyświetli to samo co wcześniej.

Jeśli to zrobisz:

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

Będziesz miał błąd, ale jeśli to zrobisz:

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

Nie będziesz miał żadnego błędu.

Możesz to zrobić:

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

I {[21] } będą zmienną całkowitą o wartości 0. ale można też zrobić to:

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

I będzie miał ten sam efekt (tj. aa będąc int Z 0 wartością).

Możesz też to zrobić:
enum {a,b,c} aa= a;
aa= 7;

I aa będą int z wartością 7.

Ponieważ nie możesz powtarzać definicji stałej symbolicznej za pomocą enum, Jak już wcześniej powiedziałem, musisz użyć tagów, jeśli chcesz zadeklarować int vars za pomocą enum:

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

Użycie typedef ma zabezpieczyć Cię przed pisaniem za każdym razem enum tag1 do zdefiniuj zmienną. Z typedef możesz po prostu wpisać Tag1:

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

Możesz też mieć:

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

Ostatnią rzeczą do powiedzenia jest to, że ponieważ mówimy o zdefiniowanych stałych symbolicznych, lepiej jest używać wielkich liter przy użyciu enum, to jest na przykład:

enum {A,B,C};

Zamiast

enum {a,b,c};
 11
Author: roggc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-13 07:40:39

Wydaje się być zamieszanie co do deklaracji.

Kiedy strategy jest przed {RANDOM, IMMEDIATE, SEARCH} jak w poniższym,

enum strategy {RANDOM, IMMEDIATE, SEARCH};

Tworzysz nowy typ o nazwie enum strategy. Jednakże, deklarując zmienną, musisz użyć samej enum strategy. Nie możesz po prostu użyć strategy. Tak więc poniższy tekst jest nieważny.

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

While, the following is valid

enum strategy {RANDOM, IMMEDIATE, SEARCH};

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

Kiedy strategy przychodzi po {RANDOM, IMMEDIATE, SEARCH}, tworzysz anonimowe enum, a następnie deklarujesz strategy jako zmienna tego typu.

Więc teraz możesz zrobić coś takiego

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

Nie możesz jednak zadeklarować żadnej innej zmiennej typu enum {RANDOM, IMMEDIATE, SEARCH}, ponieważ nigdy jej nie nazwałeś. Tak więc poniższy tekst jest nieprawidłowy

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

Możesz też połączyć obie definicje

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

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

Typedef Jak wspomniano wcześniej jest używany do tworzenia krótszej deklaracji zmiennej.

typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy;

Teraz powiedziałeś kompilatorowi, że enum {RANDOM, IMMEDIATE, SEARCH} jest synonimem strategy. Więc teraz możesz swobodnie korzystać strategy jako typ zmiennej. Nie musisz już pisać enum strategy. Poniżej obowiązuje

strategy x = RANDOM;

Możesz również połączyć Typedef wraz z nazwą enum, aby uzyskać

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

Nie ma dużej korzyści z używania tej metody poza faktem, że można teraz używać strategy i enum strategyName zamiennie.

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

enum strategyName a = RANDOM;
strategy b = SEARCH;
 9
Author: Confuse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-15 08:54:27

Jeśli zadeklarujesz nazwę do wyliczenia, nie wystąpi żaden błąd.

Jeśli nie jest zadeklarowana, musisz użyć typedef:

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

Nie wyświetli błędu...

 2
Author: Peter Mortensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-07 20:14:15

Moja ulubiona i tylko używana konstrukcja zawsze była:

typedef enum MyBestEnum
{
    /* good enough */
    GOOD = 0,
    /* even better */
    BETTER,
    /* divine */
    BEST
};
Wierzę, że to rozwiąże twój problem. Używanie nowego typu jest z mojego punktu widzenia dobrą opcją.
 2
Author: Sany,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-31 08:41:45

Odpowiedź Tarca jest najlepsza.

Większość dyskusji enum to czerwony śledź.

Porównaj ten fragment kodu:-

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

Co daje

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

Z tym, który kompiluje się bez problemu.

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

Zmienna strategy musi być ustawiona w deklaracji lub wewnątrz funkcji itp. Nie można pisać dowolnych programów-w szczególności zadań-w zasięgu globalnym.

Fakt, że użył enum {RANDOM, IMMEDIATE, SEARCH} zamiast int jest tylko istotne do tego stopnia, że zdezorientował ludzi, którzy nie mogą zobaczyć poza nim. Komunikaty o błędach redefinicji w pytaniu pokazują, że to jest to, co autor zrobił źle.

Więc teraz powinieneś być w stanie zrozumieć, dlaczego pierwszy z poniższego przykładu jest zły, a pozostałe trzy są w porządku.

Przykład 1. Źle!

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

Przykład 2. Racja.

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

Przykład 3. Racja.

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

Przykład 4. Racja.

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

Jeśli masz program roboczy, powinieneś być w stanie wkleić te fragmenty do programu i zobaczyć, że niektóre kompilują, a niektóre nie.

 1
Author: Ivan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-02 08:29:15

Próbowałem z gcc i wymyślić dla mojej potrzeby byłem zmuszony użyć ostatniej alternatywy, aby skompilować się bez błędu.

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

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
Author: gg cg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-07 21:31:06

C

enum stuff q;
enum stuff {a, b=-4, c, d=-2, e, f=-3, g} s;

Deklaracja, która działa jako wstępna definicja podpisanej liczby całkowitej s z typem kompletnym i deklaracja, która działa jako wstępna definicja podpisanej liczby całkowitej q z typem niekompletnym w zakresie (która rozwiązuje się do typu pełnego w zakresie, ponieważ definicja typu jest obecna w dowolnym miejscu zakresu) (podobnie jak każda wstępna definicja, identyfikatory q i s mogą być ponownie zadeklarowane z niepełną lub pełną wersją tego samego typu int lub enum stuff wiele razy, ale tylko raz zdefiniowany w zakresie, tj. int q = 3; i może być ponownie zdefiniowany tylko w podskopie i użyteczny tylko po definicji). Możesz również użyć pełnego typu enum stuff tylko raz w zakresie, ponieważ działa on jako definicja typu.

Definicja typu wyliczeniowego dla enum stuff jest również obecna w obszarze pliku (użyteczna przed i poniżej), jak również deklaracja typu forward (Typ enum stuff może mieć wiele deklaracji, ale tylko jedną definicja / dopełnienie w zakresie i może być przedefiniowane w podskopie). Działa również jako dyrektywa kompilatora, aby zastąpić a rvalue 0, b z -4, c z 5, d Z -2, e z -3, f z -1 i g z -2 w obecnym zakresie. Stałe wyliczenia są teraz stosowane po definicji aż do następnej redefinicji w innym wyliczeniu, które nie może być na tym samym poziomie zakresu.

typedef enum bool {false, true} bool;

//this is the same as 
enum bool {false, true};
typedef enum bool bool;

//or
enum bool {false, true};
typedef unsigned int bool;

//remember though, bool is an alias for _Bool if you include stdbool.h. 
//and casting to a bool is the same as the !! operator 

Przestrzeń nazw tagów współdzielona przez enum, struct i union jest oddzielny I musi być poprzedzony słowem kluczowym type (enum, struct lub union) W C tzn. po enum a {a} b, enum a c należy stosować, a nie a c. Ponieważ przestrzeń nazw znaczników jest oddzielona od przestrzeni nazw identyfikatorów, {[32] } jest dozwolona, ale enum a {a, b} b nie jest, ponieważ stałe są w tej samej przestrzeni nazw, co identyfikatory zmiennych, czyli przestrzeń nazw identyfikatorów. {[37] } jest również niedozwolone, ponieważ typedef-names są częścią przestrzeni nazw identyfikatorów.

Typ enum bool i stałe następują następujący wzór w C:

+--------------+-----+-----+-----+
|   enum bool  | a=1 |b='a'| c=3 |  
+--------------+-----+-----+-----+
| unsigned int | int | int | int |  
+--------------+-----+-----+-----+

+--------------+-----+-----+-----+
|   enum bool  | a=1 | b=-2| c=3 |  
+--------------+-----+-----+-----+
|      int     | int | int | int |  
+--------------+-----+-----+-----+

+--------------+-----+---------------+-----+
|   enum bool  | a=1 |b=(-)0x80000000| c=2 |
+--------------+-----+---------------+-----+
| unsigned int | int |  unsigned int | int |
+--------------+-----+---------------+-----+

+--------------+-----+---------------+-----+
|   enum bool  | a=1 |b=(-)2147483648| c=2 |
+--------------+-----+---------------+-----+
| unsigned int | int |  unsigned int | int |
+--------------+-----+---------------+-----+

+-----------+-----+---------------+------+
| enum bool | a=1 |b=(-)0x80000000| c=-2 |
+-----------+-----+---------------+------+
|    long   | int |      long     |  int |
+-----------+-----+---------------+------+

+-----------+-----+---------------+------+
| enum bool | a=1 | b=2147483648  | c=-2 |
+-----------+-----+---------------+------+
|    long   | int |      long     |  int |
+-----------+-----+---------------+------+

+-----------+-----+---------------+------+
| enum bool | a=1 | b=-2147483648 | c=-2 |
+-----------+-----+---------------+------+
|    int    | int |      int      |  int |
+-----------+-----+---------------+------+

+---------------+-----+---------------+-----+
|   enum bool   | a=1 | b=99999999999 | c=1 |
+---------------+-----+---------------+-----+
| unsigned long | int | unsigned long | int |
+---------------+-----+---------------+-----+

+-----------+-----+---------------+------+
| enum bool | a=1 | b=99999999999 | c=-1 |
+-----------+-----+---------------+------+
|    long   | int |      long     |  int |
+-----------+-----+---------------+------+

To kompiluje w C:

#include <stdio.h>
enum c j;
enum c{f, m} p;
typedef int d;
typedef int c;
enum c j;
enum m {n} ;
int main() {
  enum c j;
  enum d{l};
  enum d q; 
  enum m y; 
  printf("%llu", j);
}

C++

W C++ enums może mieć typ

enum Bool: bool {True, False} Bool;
enum Bool: bool {True, False, maybe} Bool; //error

W tej sytuacji stałe i identyfikator mają ten sam typ, bool, i wystąpi błąd, jeśli liczba nie może być reprezentowana przez ten typ. Może = 2, co nie jest bool. Również True, False i Bool nie mogą być pisane małymi literami, w przeciwnym razie będą zderzać się ze słowami kluczowymi języka. Enum również nie może mieć typu wskaźnika.

Zasady dla enum są różne w C++.

#include <iostream>
c j; //not allowed, unknown type name c before enum c{f} p; line
enum c j; //not allowed, forward declaration of enum type not allowed and variable can have an incomplete type but not when it's still a forward declaration in C++ unlike C
enum c{f, m} p;
typedef int d;
typedef int c; // not allowed in C++ as it clashes with enum c, but if just int c were used then the below usages of c j; would have to be enum c j;
[enum] c j;
enum m {n} ;
int main() {
  [enum] c j;
  enum d{l}; //not allowed in same scope as typedef but allowed here 
  d q;
  m y; //simple type specifier not allowed, need elaborated type specifier enum m to refer to enum m here
  p v; // not allowed, need enum p to refer to enum p
  std::cout << j;
}

Zmienne Enums w C++ nie są już tylko niepodpisanymi liczbami całkowitymi itp., są również typu enum i mogą być przypisane tylko stałe w enum. Można to jednak odrzucić.

#include <stdio.h>
enum a {l} c;
enum d {f} ;
int main() {
  c=0; // not allowed;
  c=l;
  c=(a)1;
  c=(enum a)4;
  printf("%llu", c); //4
}

Klasy Enum

enum struct jest identyczny z enum class

#include <stdio.h>
enum class a {b} c;
int main() {
  printf("%llu", a::b<1) ; //not allowed
  printf("%llu", (int)a::b<1) ;
  printf("%llu", a::b<(a)1) ;
  printf("%llu", a::b<(enum a)1);
  printf("%llu", a::b<(enum class a)1) ; //not allowed 
  printf("%llu", b<(enum a)1); //not allowed
}

Operator rozdzielczości zakresu może być nadal używany dla enum nieoznaczonych.

#include <stdio.h>
enum a: bool {l, w} ;
int main() {
  enum a: bool {w, l} f;
  printf("%llu", ::a::w);
}

Ale ponieważ w nie może być zdefiniowane jako coś innego w zakresie, nie ma różnicy między ::w a ::a::w

 0
Author: Lewis Kelsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55