Я не уверен, каков правильный синтаксис для использования C перечислений. У меня есть следующий код:
enum {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy = IMMEDIATE;
Но это не компилируется со следующей ошибкой:
error: conflicting types for ‘strategy’
error: previous declaration of ‘strategy’ was here
Что я делаю не так?
strategy
что имеет анонимный перечисляемый тип, и присваивает ему одно из объявленных значений этого типа. Более того, если я оберну код, представленный в другой тривиальнойmain()
функции, он прекрасно скомпилируется для меня, даже без предупреждения, с помощью gcc 4.4.7. Некоторые ответы подразумевают то же самое, хотя и не так много слов.strategy = IMMEDIATE;
как объявление. У этого есть форма, которая была бы законна в до-ANSI C, но в современном C это незаконно. Назначения не разрешены в области файла.enum strategy { ... };
определяет перечислимый тип namedenum strategy
, гдеstrategy
находится тег.enum { ... } strategy;
определяет анонимный перечислимый тип (без тега) и единственный объект этого типа с именемstrategy
. Оба совершенно законны; они просто имеют в виду разные вещи.Ответы:
Объявление переменной enum выполняется следующим образом:
Тем не менее, вы можете использовать
typedef
для сокращения объявлений переменных, например так:Хорошая идея - иметь соглашение об именах, чтобы различать типы и переменные:
источник
enum MyEnum {} myVar;
и затем использовать переменнуюmyVar
следующим образом:myVar = SOMEENUMCONSTANT;
Стоит отметить, что вам не нужно
typedef
. Вы можете просто сделать это следующим образомЭто вопрос стиля, предпочитаете ли вы
typedef
. Без этого, если вы хотите сослаться на тип перечисления, вам нужно использоватьenum strategy
. С этим можно просто сказатьstrategy
.Оба способа имеют свои плюсы и минусы. Один из них более многословный, но хранит идентификаторы типов в пространстве имен тегов, где они не будут конфликтовать с обычными идентификаторами (подумайте
struct stat
и оstat
функции: они тоже не конфликтуют), и где вы сразу увидите, что это тип. Другой короче, но переносит идентификаторы типов в обычное пространство имен.источник
enum
ключевое слово в обеих строках.enum strategy { RANDOM, IMMEDIATE, SEARCH };
тогда, когда вам нужен экземпляр этого enum: `enum стратегии myEnum;Вы пытаетесь объявить
strategy
дважды, и именно поэтому вы получаете вышеупомянутую ошибку. Следующие работы без каких-либо жалоб (составлено сgcc -ansi -pendantic -Wall
):Если вместо вышеизложенного, вторая строка была изменена на:
Из предупреждений вы можете легко увидеть свою ошибку:
Таким образом, компилятор принял
strategy = IMMEDIATE
объявление переменнойstrategy
с типом по умолчаниюint
, но ранее уже существовало объявление переменной с этим именем.Однако, если вы поместите присвоение в
main()
функцию, это будет действительный код:источник
Когда ты говоришь
вы создаете единственную переменную экземпляра, называемую «стратегией» безымянного перечисления. Это не очень полезная вещь - вам нужен typedef:
источник
Как написано, нет ничего плохого в вашем коде. Вы уверены, что не сделали что-то вроде
На какие строки указывают сообщения об ошибках? Когда говорится, что «предыдущая декларация« стратегии »была здесь», что здесь «что» и что она показывает?
источник
strategy = IMMEDIATE;
в области видимости файла. Назначение не может происходить в области видимости файла вне всех функций. Таким образом, компилятор попытался сделать все возможное из ошибки и предположил, что он имел в видуint strategy = IMMEDIATE;
, в этот момент произошел конфликт.@ThoAppelsin в своем комментарии к опубликованному вопросу прав. Фрагмент кода размещен в вопросе, он действителен и без ошибок. Ошибка у вас должна быть из-за другого неправильного синтаксиса в любом другом месте вашего исходного файла c.
enum{a,b,c};
определяет три символические константы (a
,b
иc
), которые являются целыми числами со значениями0
,1
и2
соответственно, но когда мы используемenum
это, потому что мы обычно не заботимся о конкретном целочисленном значении, мы больше заботимся о значении имени символической константы. Это означает, что вы можете иметь это:и это будет выводить
1
.Это также будет действительным:
и будет выводить то же, что и раньше.
Если вы делаете это:
у вас будет ошибка, но если вы сделаете это:
у вас не будет никакой ошибки.
ты можешь сделать это:
и
aa
будет целочисленной переменной со значением0
. но вы также можете сделать это:и будет иметь тот же эффект (то есть,
aa
будучиint
со0
значением).Вы также можете сделать это:
и
aa
будетint
со значением7
.поскольку вы не можете повторить символьное определение константы с использованием
enum
, как я уже говорил ранее, вы должны использовать теги, если хотите объявитьint
переменные с использованиемenum
:польза от
typedef
него заключается в том, чтобы защитить вас от записи каждый разenum tag1
для определения переменной. С помощьюtypedef
вы можете просто набратьTag1
:Вы также можете иметь:
Последнее, что нужно сказать, это то, что, поскольку мы говорим об определенных символических константах, при использовании лучше использовать заглавные буквы
enum
, например:вместо того
источник
Стоит отметить, что в C ++ вы можете использовать «enum» для определения нового типа без использования оператора typedef.
Я считаю этот подход намного более дружелюбным.
[править - уточнил статус C ++ - у меня это было изначально, потом удалил!]
источник
typedef
, либо указатьenum
в объявлении переменной также: enum Strategy {RANDOM, IMMEDIATE, SEARCH}; ... enum Strategy myStrategy = IMMEDIATE;enum Strategy
. Я сделал это, см. Ниже.Кажется, есть путаница в декларации.
Когда
strategy
приходит раньше,{RANDOM, IMMEDIATE, SEARCH}
как в следующем,вы создаете новый тип с именем
enum strategy
. Однако при объявлении переменной вам нужно использоватьenum strategy
себя. Вы не можете просто использоватьstrategy
. Таким образом, следующее недействительно.Пока действует следующее
Когда
strategy
приходит после{RANDOM, IMMEDIATE, SEARCH}
, вы создаете анонимное перечисление, а затем объявляетеstrategy
переменную этого типа.Так что теперь вы можете сделать что-то вроде
Однако вы не можете объявить любую другую переменную типа,
enum {RANDOM, IMMEDIATE, SEARCH}
потому что вы никогда не называли ее. Так что следующее неверноВы можете объединить оба определения тоже
Typedef
как отмечалось ранее, используется для создания более короткого объявления переменной.Теперь вы сказали компилятору, что
enum {RANDOM, IMMEDIATE, SEARCH}
является синонимомstrategy
. Так что теперь вы можете свободно использоватьstrategy
как тип переменной. Вам не нужноenum strategy
больше печатать . Следующее действует в настоящее времяВы также можете комбинировать Typedef вместе с именем enum, чтобы получить
Существует не так много преимуществ использования этого метода, кроме того, что вы можете теперь использовать
strategy
иenum strategyName
взаимозаменяемо.источник
typedef enum strategy {RANDOM, IMMEDIATE, SEARCH} strategy
илиtypedef enum strategy {RANDOM, IMMEDIATE, SEARCH} strategy_type
. Это имеет какое-то преимущество передtypedef enum {RANDOM, IMMEDIATE, SEARCH} strategy
? Не могли бы вы добавить их в свой ответ для полноты?Если вы объявляете имя для перечисления, никакой ошибки не произойдет.
Если не объявлено, вы должны использовать
typedef
:Это не будет отображать ошибку ...
источник
Моя любимая и единственная использованная конструкция всегда была:
Я верю, что это устранит вашу проблему. Использование нового типа является, с моей точки зрения, правильным вариантом.
источник
Ответ Тарка самый лучший.
Большая часть обсуждения enum - красная сельдь.
Сравните этот фрагмент кода: -
который дает
с этим, который компилируется без проблем.
Переменная
strategy
должна быть установлена при объявлении или внутри функции и т. Д. Вы не можете писать произвольное программное обеспечение - в частности, назначения - в глобальной области видимости.Тот факт, что он использовал enum {RANDOM, IMMEDIATE, SEARCH} вместо int, имеет отношение только к той степени, в которой он запутал людей, которые не могут видеть за его пределами. Сообщения об ошибках переопределения в вопросе показывают, что автор поступил неправильно.
Итак, теперь вы сможете понять, почему первый из приведенных ниже примеров неверен, а остальные три в порядке.
Пример 1. НЕПРАВИЛЬНО!
Пример 2. ПРАВО.
Пример 3. ПРАВО.
Пример 4. ПРАВО.
Если у вас есть работающая программа, вы можете просто вставить эти фрагменты в вашу программу и увидеть, что некоторые компилируются, а некоторые нет.
источник
Я попытался с gcc и придумал для себя, я был вынужден использовать последнюю альтернативу, чтобы компилировать без ошибок.
typedef enum состояние {a = 0, b = 1, c = 2} состояние ;
источник
new
плохой выбор идентификаторов в семействе C, потому что это оператор в C ++.С
Объявление, которое действует как предварительное определение целого числа
s
со знаком с полным типом, и объявление, которое действует как предварительное определение целого числаq
со знаком с неполным типом в области (которое преобразуется в полный тип в области, поскольку определение типа присутствует в любом месте область действия) (как и любое предварительное определение, идентификаторыq
иs
могут быть повторно объявлены с неполной или полной версией того же типаint
илиenum stuff
несколько раз, но только один раз определены в области, то есть int q = 3; и могут быть переопределены только в подскопе, и можно использовать только после определения). Также вы можете использовать только полный типenum stuff
в области видимости, потому что он действует как определение типа.Определение типа перечисления для компилятора
enum stuff
также присутствует в области видимости файла (может использоваться до и ниже), а также в прямом объявлении типа (типenum stuff
может иметь несколько объявлений, но только одно определение / завершение в области действия и может быть переопределен в подобласти). , Он также действует как директива компилятора для заменыa
на rvalue0
,b
с-4
,c
с5
,d
с-2
,e
с-3
,f
с-1
иg
с-2
в текущей области видимости. Константы перечисления теперь применяются после определения до следующего переопределения в другом перечислении, которое не может быть на том же уровне области действия.Пространство имен тегов, совместно используемое enum, struct и union, является отдельным и должно начинаться с префикса с помощью ключевого слова type (enum, struct или union) в C, т. Е. После
enum a {a} b
,enum a c
должно использоваться и не использоватьсяa c
. Поскольку пространство имен тега отделено от пространства имен идентификатора,enum a {a} b
оно разрешено, ноenum a {a, b} b
не потому, что константы находятся в том же пространстве имен, что и идентификаторы переменных, пространство имен идентификатора.typedef enum a {a,b} b
также не допускается, потому что typedef-names являются частью пространства имен идентификатора.Тип
enum bool
и константы следуют следующей схеме в C:Это хорошо компилируется в C:
C ++
В C ++ перечисления могут иметь тип
В этой ситуации все константы и идентификатор имеют одинаковый тип, bool, и произойдет ошибка, если число не может быть представлено этим типом. Возможно = 2, что не является булом. Кроме того, True, False и Bool не могут быть строчными, иначе они будут конфликтовать с ключевыми словами языка. Перечисление также не может иметь тип указателя.
Правила для перечислений различны в C ++.
Переменные перечисления в C ++ больше не являются целыми числами без знака и т. Д., Они также имеют тип enum и могут быть назначены только константы в перечислении. Это может однако быть отброшено.
Enum классы
enum struct
идентичноenum class
Оператор разрешения контекста все еще может использоваться для неперечисленных перечислений.
Но поскольку вес не может быть определена как - то еще в объеме, нет никакой разницы между
::w
и::a::w
источник