Nie jestem pewien, jaka jest właściwa składnia do używania znaków C. Mam następujący kod:
enum {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy = IMMEDIATE;
Ale to się nie kompiluje, z następującym błędem:
error: conflicting types for ‘strategy’
error: previous declaration of ‘strategy’ was here
Co ja robię źle?
strategy
że ma anonimowy wyliczony typ i przypisuje mu jedną z zadeklarowanych wartości tego typu. Co więcej, jeśli zawijam kod przedstawiony w trywialnejmain()
funkcji, to kompiluje się dla mnie dobrze, nawet bez ostrzeżenia, z gcc 4.4.7. Niektóre odpowiedzi sugerują to samo, choć nie w tak wielu słowach.strategy = IMMEDIATE;
jako deklarację. Ma formę, która byłaby legalna w czasach poprzedzających ANSI C, ale we współczesnym C jest to nielegalne. Przydziały nie są dozwolone w zakresie plików.enum strategy { ... };
definiuje wyliczony typ o nazwieenum strategy
, gdziestrategy
jest tag.enum { ... } strategy;
definiuje anonimowy wyliczony typ (bez znacznika) i pojedynczy obiekt tego typu o nazwiestrategy
. Oba są całkowicie legalne; oznaczają tylko różne rzeczy.Odpowiedzi:
Zadeklarowanie zmiennej wyliczeniowej odbywa się w następujący sposób:
Możesz jednak użyć a,
typedef
aby skrócić deklaracje zmiennych, tak jak to:Posiadanie konwencji nazewnictwa w celu rozróżnienia typów i zmiennych jest dobrym pomysłem:
źródło
enum MyEnum {} myVar;
a następnie użyć zmiennejmyVar
w następujący sposób:myVar = SOMEENUMCONSTANT;
Warto podkreślić, że nie trzeba
typedef
. Możesz to zrobić w następujący sposóbTo pytanie w stylu, czy wolisz
typedef
. Bez niego, jeśli chcesz odwoływać się do typu wyliczenia, musisz użyćenum strategy
. Dzięki niemu możesz po prostu powiedziećstrategy
.Oba sposoby mają swoje zalety i wady. Ten jest bardziej niewygodny, ale przechowuje identyfikatory typów w przestrzeni nazw znaczników, gdzie nie będą konfliktować ze zwykłymi identyfikatorami (pomyśl
struct stat
istat
funkcja: te też nie powodują konfliktu) i gdzie natychmiast zobaczysz, że jest to typ. Drugi jest krótszy, ale wprowadza identyfikatory typów do zwykłej przestrzeni nazw.źródło
enum
słowa kluczowego w obu liniach.enum strategy { RANDOM, IMMEDIATE, SEARCH };
wtedy, gdy chcesz mieć instancję tego wyliczenia: `enum strategia myEnum;Próbujesz zadeklarować
strategy
dwa razy i dlatego otrzymujesz powyższy błąd. Poniższe działa bez żadnych skarg (z kompilacjągcc -ansi -pendantic -Wall
):Jeśli zamiast powyższego, druga linia została zmieniona na:
Z ostrzeżeń możesz łatwo zobaczyć swój błąd:
Tak więc kompilator wziął
strategy = IMMEDIATE
deklarację zmiennejstrategy
o typie domyślnymint
, ale była już poprzednia deklaracja zmiennej o tej nazwie.Jeśli jednak umieścisz przypisanie w
main()
funkcji, będzie to poprawny kod:źródło
Kiedy powiesz
tworzysz zmienną o pojedynczej instancji, zwaną „strategią” bezimiennego wyliczenia. To nie jest bardzo przydatna rzecz - potrzebujesz typedef:
źródło
Jak napisano, nie ma nic złego w kodzie. Jesteś pewien, że nie zrobiłeś czegoś takiego
Jakie linie wskazują komunikaty o błędach? Kiedy mówi „poprzednia deklaracja„ strategii ”była tutaj”, co jest „tutaj” i co to pokazuje?
źródło
strategy = IMMEDIATE;
w zakresie plików. Przypisanie nie może nastąpić w zakresie plików poza wszystkimi funkcjami. Tak więc kompilator próbował zrobić wszystko, co w jego mocy, i przyjął, że miałint strategy = IMMEDIATE;
na myśli , w którym momencie nastąpił konflikt.@ThoAppelsin w swoim komentarzu do zadanego pytania ma rację. Fragment kodu opublikowany w pytaniu jest prawidłowy i bez błędów. Wystąpił błąd, ponieważ inna zła składnia w innym miejscu pliku źródłowego c.
enum{a,b,c};
definiuje trzy stałe symboliczne (a
,b
ic
), które są liczbami całkowitymi z wartościami0
,1
i2
odpowiednio, ale kiedyenum
go używamy , to dlatego, że zwykle nie dbamy o konkretną wartość całkowitą, bardziej zależy nam na znaczeniu stałej symbolicznej. Oznacza to, że możesz mieć to:i to da wynik
1
.To również będzie ważne:
i wyświetli takie same jak poprzednio.
Jeśli to zrobisz:
wystąpi błąd, ale jeśli to zrobisz:
nie wystąpi żaden błąd.
możesz to zrobić:
i
aa
będzie zmienną całkowitą o wartości0
. ale możesz również to zrobić:i mieć ten sam efekt, (to znaczy,
aa
będącint
z0
wartości).możesz również to zrobić:
i
aa
będzieint
z wartością7
.ponieważ nie można powtórzyć stałej symbolicznej przy użyciu
enum
, jak już powiedziałem, musisz użyć tagów, jeśli chcesz zadeklarowaćint
zmienne przy użyciuenum
:jego użycie
typedef
ma uchronić cię przed pisaniem za każdym razem,enum tag1
aby zdefiniować zmienną. Dziękitypedef
możesz po prostu wpisaćTag1
:Możesz również mieć:
Ostatnią rzeczą do powiedzenia jest to, że skoro mówimy o zdefiniowanych stałych symbolicznych, lepiej jest używać liter pisanych wielkimi literami
enum
, np.zamiast
źródło
Warto wspomnieć, że w C ++ można użyć „enum” do zdefiniowania nowego typu bez potrzeby używania instrukcji typedef.
Uważam to podejście za bardziej przyjazne.
[edytuj - wyjaśniono status C ++ - miałem to pierwotnie, a następnie usunąłem!]
źródło
typedef
, albo też podaćenum
w zmiennej deklaracji: enum Strategy {RANDOM, NATYCHMIAST, SZUKAJ}; ... strategia enum myStrategy = NATYCHMIAST;enum Strategy
. Zrobiłem to, patrz poniżej.Wydaje się, że istnieje zamieszanie co do deklaracji.
Kiedy
strategy
nastąpi wcześniej,{RANDOM, IMMEDIATE, SEARCH}
jak poniżej,tworzysz nowy typ o nazwie
enum strategy
. Jednak deklarując zmienną, musisz użyć jejenum strategy
samej. Nie możesz tak po prostu użyćstrategy
. Zatem poniższe informacje są nieprawidłowe.Chociaż poniższe informacje są prawidłowe
Kiedy
strategy
przyjdzie później{RANDOM, IMMEDIATE, SEARCH}
, tworzysz anonimowy wyliczenie, a następnie deklarujesz,strategy
że jest zmienną tego typu.Teraz możesz zrobić coś takiego
Nie można jednak zadeklarować żadnej innej zmiennej typu,
enum {RANDOM, IMMEDIATE, SEARCH}
ponieważ nigdy jej nie nadano. Zatem poniższe informacje są nieprawidłoweMożesz także połączyć obie definicje
Typedef
jak wspomniano wcześniej, służy do tworzenia krótszej deklaracji zmiennej.Teraz powiedziałeś kompilatorowi, który
enum {RANDOM, IMMEDIATE, SEARCH}
jest synonimemstrategy
. Teraz możesz swobodnie używaćstrategy
jako typu zmiennej. Nie musiszenum strategy
już pisać . Następujące informacje są teraz aktualneMożesz także połączyć Typedef z nazwą wyliczenia, aby uzyskać
Korzystanie z tej metody nie ma wiele zalet poza tym, że można jej teraz używać
strategy
ienum strategyName
zamieniać.źródło
typedef enum strategy {RANDOM, IMMEDIATE, SEARCH} strategy
lubtypedef enum strategy {RANDOM, IMMEDIATE, SEARCH} strategy_type
. Czy ma to jakąś przewagętypedef enum {RANDOM, IMMEDIATE, SEARCH} strategy
? Czy chciałbyś rozważyć dodanie ich do swojej odpowiedzi?Jeśli podasz nazwę wyliczenia, nie wystąpi błąd.
Jeśli nie zostało zadeklarowane, musisz użyć
typedef
:Nie wyświetli błędu ...
źródło
Moją ulubioną i używaną konstrukcją zawsze była:
Wierzę, że to usunie twój problem. Używanie nowego typu jest z mojego punktu widzenia właściwą opcją.
źródło
Odpowiedź Tarca jest najlepsza.
Znaczna część dyskusji wyliczeniowej to czerwony śledź.
Porównaj ten fragment kodu: -
co daje
z tym, który kompiluje się bez problemu.
Zmienna
strategy
musi być ustawiona w deklaracji lub wewnątrz funkcji itp. Nie można pisać dowolnego oprogramowania - w szczególności przypisań - w zakresie globalnym.Fakt, że użył enum {RANDOM, NATYCHMIAST, SZUKAJ} zamiast int jest istotny tylko w takim stopniu, w jakim wprawił w zakłopotanie ludzi, którzy nie widzą poza tym. Komunikaty o błędach redefinicji w pytaniu pokazują, że autor postąpił źle.
Więc teraz powinieneś zobaczyć, dlaczego pierwszy z poniższych przykładów jest nieprawidłowy, a pozostałe trzy są w porządku.
Przykład 1. ŹLE!
Przykład 2. PRAWO.
Przykład 3. PRAWO.
Przykład 4. PRAWO.
Jeśli masz działający program, powinieneś po prostu móc wkleić te fragmenty do swojego programu i zobaczyć, że niektóre kompilują, a inne nie.
źródło
Próbowałem z gcc i wymyśliłem dla mojej potrzeby byłem zmuszony użyć ostatniej alternatywy, aby skompilować bez błędu.
typedef enum state {a = 0, b = 1, c = 2} stan ;
źródło
new
jest złym wyborem identyfikatorów w rodzinie C, ponieważ jest operatorem w C ++.do
Deklaracja, która działa jako wstępna definicja podpisanej liczby całkowitej
s
z pełnym typem i deklaracja, która działa jako wstępna definicja podpisanej liczby całkowitejq
z niekompletnym typem w zakresie (który rozwiązuje się do pełnego typu w zakresie, ponieważ definicja typu znajduje się w dowolnym miejscu w zakres) (jak każda wstępna definicja, identyfikatoryq
is
mogą być ponownie zadeklarowane z niekompletną lub pełną wersją tego samego typuint
lubenum stuff
wiele razy, ale tylko raz zdefiniowane w zakresie, tj. int q = 3; i mogą być ponownie zdefiniowane tylko w podzakresie, oraz możliwe do użycia tylko po definicji). Możesz także użyć pełnego typuenum stuff
raz w zakresie, ponieważ działa on jak definicja typu.Definicja typu wyliczenia kompilatora dla
enum stuff
jest również obecna w zakresie pliku (użyteczne przed i poniżej), a także w deklaracji typu forward (typenum stuff
może mieć wiele deklaracji, ale tylko jedną definicję / uzupełnienie w zakresie i może być przedefiniowany w podskopie) . Działa również jako dyrektywy kompilatora do zastąpieniaa
z rvalue0
,b
z-4
,c
z5
,d
z-2
,e
z-3
,f
z-1
, ag
ze-2
w obecnym zakresie. Stałe wyliczenia obowiązują teraz po definicji do następnej redefinicji w innym wyliczeniu, które nie może być na tym samym poziomie zakresu.Przestrzeń nazw znaczników współdzielona przez enum, struct i union jest osobna i musi być poprzedzona słowem kluczowym type (enum, struct lub union) w C, tzn. Po
enum a {a} b
,enum a c
musi być używana, a niea c
. Ponieważ przestrzeń nazw znacznika jest oddzielna od przestrzeni nazw identyfikatora,enum a {a} b
jest dozwolona, aleenum a {a, b} b
nie dlatego, że stałe znajdują się w tej samej przestrzeni nazw, co identyfikatory zmiennych, przestrzeń nazw identyfikatora.typedef enum a {a,b} b
jest również niedozwolone, ponieważ typedef-names są częścią przestrzeni nazw identyfikatora.Typ
enum bool
i stałe są zgodne z następującym wzorcem w C:Kompiluje się dobrze w C:
C ++
W C ++ wyliczenia mogą mieć typ
W tej sytuacji wszystkie 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 boolem. Również True, False i Bool nie mogą być pisane małymi literami, w przeciwnym razie będą kolidować ze słowami kluczowymi języka. Wyliczenie również nie może mieć typu wskaźnika.
Zasady wyliczania są różne w C ++.
Zmienne wyliczające w C ++ nie są już tylko liczbami całkowitymi bez znaku itp., Są również typu wyliczeniowego i można im przypisywać tylko stałe w wyliczeniu. Można to jednak odrzucić.
Klasy enum
enum struct
jest identyczny zenum class
Operator rozdzielczości zakresu nadal może być używany do wyliczeń nieposiadających zasięgu.
Ale ponieważ w nie można zdefiniować jako czegoś innego w zakresie, nie ma różnicy między
::w
i::a::w
źródło