287

I'm not sure what is the proper syntax for using C enums. I have the following code:

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

But this does not compile, with the following error:

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

What am I doing wrong?

lindelof
  • 34,556
  • 31
  • 99
  • 140
  • 7
    Years-old question, probably nobody will see this; but why is this giving an error? It should work perfectly well as it is in the question as far as my knowledge goes. – Utkan Gezer Mar 15 '14 at 16:37
  • @ThoAppelsin - Necroing the necro here, but here it goes - Check Johannes Schaub - litb's answer. The syntax is wrong, enum name (strategy) goes before enum values (random, immediate, search). – Nitkov Oct 10 '14 at 07:55
  • 2
    @Solver why is this syntax wrong? – MCG Oct 22 '15 at 15:51
  • @MCG As per [this](https://msdn.microsoft.com/en-us/library/whbyts4t.aspx), the identifier `strategy` should come after `enum` and before enum-list. In this question, it comes last. – Nitkov Oct 23 '15 at 08:00
  • 6
    @MCQ, necroing the necro'd necro: The syntax presented in the question is *not* wrong in C. It declares `strategy` as having an anonymous enumerated type, and assigns one of the declared values of that type to it. Moreover, if I wrap the code presented in an otherwise trivial `main()` function then it compiles fine for me, without even a warning, with gcc 4.4.7. Some of the answers imply the same, albeit not in so many words. – John Bollinger Feb 09 '16 at 14:50
  • 1
    This works BRILLIANTLY fine on `gcc` version 5.3.0. COMPILES fine and PRINTS output too. – John Strood Jul 28 '16 at 14:31
  • 7
    Most of the answers are missing the fact that the two lines of code in the question are not just a snippet. **They're the entire source file.** If those two lines are included in the body of a function, there is no error. If they appear at file scope, outside any function declaration, you'll get the errors the OP asked about (plus some others when I tried it). The fundamental problem is that the compiler is trying to treat `strategy = IMMEDIATE;` as a declaration. It has a form that would have been legal in pre-ANSI C, but in modern C it's illegal. Assignments are not permitted at file scope. – Keith Thompson Sep 21 '17 at 22:08
  • @John Strood This is how I learned to write enums in C although I agree with [Sam Hartman](https://stackoverflow.com/questions/46353655/c99-enum-need-clarification?noredirect=1#comment79667835_46353655) that separation of definition and declaration should occur – Mushy Sep 21 '17 at 22:17
  • 3
    @Solver: `enum strategy { ... };` defines an enumerated type named `enum strategy`, where `strategy` is the tag. `enum { ... } strategy;` defines an anonymous enumerated type (no tag) *and* a single object of that type named `strategy`. Both are perfectly legal; they just mean different things. – Keith Thompson Sep 21 '17 at 22:29

13 Answers13

456

It's worth pointing out that you don't need a typedef. You can just do it like the following

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

It's a style question whether you prefer typedef. Without it, if you want to refer to the enumeration type, you need to use enum strategy. With it, you can just say strategy.

Both ways have their pro and cons. The one is more wordy, but keeps type identifiers into the tag-namespace where they won't conflict with ordinary identifiers (think of struct stat and the stat function: these don't conflict either), and where you immediately see that it's a type. The other is shorter, but brings type identifiers into the ordinary namespace.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 7
    It shouldn't be the accepted answer because it's wrong. You cannot use enum strategy { ... }; in C -- you can and should do it in C++ though. – Clearer May 06 '14 at 07:31
  • 19
    @Clearer: This code works perfectly. Here's a working example: https://ideone.com/T0YV17 Note that it uses the `enum` keyword on both lines. – RichieHindle May 06 '14 at 07:47
  • Or "typedef enum strategy { RANDOM, IMMEDIATE, SEARCH } strategy_t;" and the dev using the enum can use whichever convention they want. – Andy Nugent Nov 13 '14 at 12:05
  • this works excellent: `enum strategy { RANDOM, IMMEDIATE, SEARCH };` then when you want an instance of that enum: `enum strategy myEnum; – user3629249 Jan 24 '16 at 04:37
  • 2
    @AndyNugent don't do that! *_t types are reserved by POSIX – osvein Aug 16 '17 at 21:14
  • @Clearer I don't know about earlier standards but it is perfectly valid in C99. – osvein Aug 16 '17 at 21:20
  • Why won't `enum MyEnum {} useEnum;` work properly in C99? Why is there a need to use the `enum MyEnum variableName`? In C using Visual Studio 2015 the aforementioned works fine without all the additional typing needed – Mushy Sep 21 '17 at 21:35
396

Declaring an enum variable is done like this:

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

However, you can use a typedef to shorten the variable declarations, like so:

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

Having a naming convention to distinguish between types and variables is a good idea:

typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy_type;
strategy_type my_strategy = IMMEDIATE;
Martin
  • 940
  • 6
  • 26
RichieHindle
  • 272,464
  • 47
  • 358
  • 399
60

You're trying to declare strategy twice, and that's why you're getting the above error. The following works without any complaints (compiled with 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;
}

If instead of the above, the second line were changed to:

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

From the warnings, you could easily see your mistake:

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

So the compiler took strategy = IMMEDIATE for a declaration of a variable called strategy with default type int, but there was already a previous declaration of a variable with this name.

However, if you placed the assignment in the main() function, it would be a valid code:

#include <stdio.h>

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

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

    return 0;
}
HenrikS
  • 4,170
  • 3
  • 34
  • 33
Tarc
  • 3,214
  • 3
  • 29
  • 41
52

When you say

enum {RANDOM, IMMEDIATE, SEARCH} strategy;

you create a single instance variable, called 'strategy' of a nameless enum. This is not a very useful thing to do - you need a typedef:

typedef enum {RANDOM, IMMEDIATE, SEARCH} StrategyType; 
StrategyType strategy = IMMEDIATE;
  • 10
    Why is this not useful? If I don't care about the name of the type, why should I give it one? The only thing intended here was to name the variable, so it's possible to assign new values to it. – MSalters Jul 09 '09 at 11:09
  • 3
    I said it was not VERY useful, and I don't believe it is. Certainly, I don't use this pattern in my own code. YMMV. –  Jul 09 '09 at 11:13
  • 1
    But why is it not a very useful thing to do? – Horse SMith Nov 13 '14 at 22:20
  • 4
    @HorseSMith An unnamed enum is not very useful because you can't have any other variable of that type, or function parameter or return value. If the **one variable** is all you need, then it's fine. – Bob Stein Jul 25 '15 at 14:05
  • 3
    Somebody not using anonymous enums doesn't prove that they have no use. You don't need typedef. Some code guidelines (kernel.org/doc/Documentation/CodingStyle) even discourage it. – martinkunev Nov 19 '15 at 09:20
  • 2
    This answer is ALSO misleading. Tarc's answer is the only right one here. – nightpool Feb 27 '17 at 00:12
12

As written, there's nothing wrong with your code. Are you sure you haven't done something like

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

What lines do the error messages point to? When it says "previous declaration of 'strategy' was here", what's "here" and what does it show?

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • 7
    He probably did `strategy = IMMEDIATE;` at file-scope. An assignment can't happen at file-scope outside all functions. So the compiler tried to do the best out of the error and assumed he meant `int strategy = IMMEDIATE;`, at which point the conflict happened. – Johannes Schaub - litb Jul 09 '09 at 16:06
  • 2
    This is the best answer, there is so mucn confusion in the other answers it's painful. – unwind Apr 29 '15 at 08:56
11

It's worth mentioning that in C++ you can use "enum" to define a new type without needing a typedef statement.

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

I find this approach a lot more friendly.

[edit - clarified C++ status - I had this in originally, then removed it!]

Roddy
  • 66,617
  • 42
  • 165
  • 277
  • Yes, you should never use typedef with enums (or structs, unions etc.) in C++. –  Jul 09 '09 at 08:42
  • 17
    This question is for C, not for C++. In C, the above code is invalid - you either have to use `typedef`, or specify `enum` in variable declaration as well: enum Strategy {RANDOM, IMMEDIATE, SEARCH}; ... enum Strategy myStrategy = IMMEDIATE; – Pavel Minaev Jul 09 '09 at 08:56
  • @pavel - my bad. I had "in C++" in originally, then did some research which seemed to contradict that. – Roddy Jul 09 '09 at 09:16
  • @Pavel I think it should be a separate answer describing the benefits of using `enum Strategy`. I did that, see below. – Johannes Schaub - litb Jul 09 '09 at 16:23
11

@ThoAppelsin in his comment to question posted is right. The code snippet posted in the question it is valid and with no errors. The error you have must be because other bad syntax in any other place of your c source file. enum{a,b,c}; defines three symbolic constants (a, b and c) which are integers with values 0,1 and 2 respectively, but when we use enum it is because we don't usually care about the specific integer value, we care more about the meaning of the symbolic constant name. This means you can have this:

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

and this will output 1.

This also will be valid:

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

and will output the same as before.

If you do this:

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

you will have an error, but if you do this:

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

you will not have any error.

you can do this:

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

and aa will be an integer variable with value 0. but you can also do this:

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

and will have the same effect (that is, aa being an int with 0 value).

you can also do this:

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

and aa will be int with value 7.

because you cannot repeat symbolic constant definition with the use of enum, as i have said previously, you must use tags if you want to declare int vars with the use of enum:

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

the use of typedef it is to safe you from writing each time enum tag1 to define variable. With typedef you can just type Tag1:

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

You can also have:

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

Last thing to say it is that since we are talking about defined symbolic constants it is better to use capitalized letters when using enum, that is for example:

enum {A,B,C};

instead of

enum {a,b,c};
roggc
  • 111
  • 1
  • 6
9

There seems to be a confusion about the declaration.

When strategycomes before {RANDOM, IMMEDIATE, SEARCH} as in the following,

enum strategy {RANDOM, IMMEDIATE, SEARCH};

you are creating a new type named enum strategy. However, when declaring the variable, you need to use enum strategy itself. You cannot just use strategy. So the following is invalid.

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];

When strategy comes after {RANDOM, IMMEDIATE, SEARCH}, you are creating an anonymous enum and then declaring strategy to be a variable of that type.

So now, you can do something like

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

However, you cannot declare any other variable of type enum {RANDOM, IMMEDIATE, SEARCH} because you have never named it. So the following is invalid

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

You can combine both the definitions too

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

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

Typedef as noted before is used for creating a shorter variable declaration.

typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy;

Now you have told compiler that enum {RANDOM, IMMEDIATE, SEARCH} is synonomous to strategy. So now you can freely use strategy as variable type. You don't need to type enum strategy anymore. The following is valid now

strategy x = RANDOM;

You can also combine Typedef along with enum name to get

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

There's not much advantage of using this method apart from the fact that you can now use strategy and enum strategyName interchangeably.

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

enum strategyName a = RANDOM;
strategy b = SEARCH;
Confuse
  • 5,646
  • 7
  • 36
  • 58
  • 1
    Great answer. I've also come across enum definitions written like this: `typedef enum strategy {RANDOM, IMMEDIATE, SEARCH} strategy` or `typedef enum strategy {RANDOM, IMMEDIATE, SEARCH} strategy_type`. Does that have any advantage over `typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy`? Would you consider adding these to your answer, for completeness? – tjalling Dec 14 '16 at 23:20
  • Yes. I modified my answer. As per my knowledge, there's isn't any major advantage in general case. – Confuse Dec 15 '16 at 08:55
  • 2
    Great, your answer covers it all now, thanks. A shame it's so far down the list of answers, not in the least because it _explicitly_ addresses the original question, with proper explanation. – tjalling Dec 15 '16 at 12:35
2

If you declare the name for enumeration no error will occur.

If not declared, you have to use a typedef:

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

It will not display an error...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
2

My favorite and only used construction always was:

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

I believe that this will remove your problem you have. Using new type is from my point of view right option.

Sany
  • 103
  • 2
  • 8
1

Tarc's answer is the best.

Much of the enum discussion is a red herring.

Compare this code snippet:-

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

which gives

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

with this one which compiles with no problem.

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

The variable strategy needs to be set at declaration or inside a function etc. You cannot write arbitrary software - assignments in particular - at the global scope.

The fact that he used enum {RANDOM, IMMEDIATE, SEARCH} instead of int is only relevant to the extent that it has confused people that can't see beyond it. The redefinition error messages in the question show that this is what the author has done wrong.

So now you should be able to see why the first of the example below is wrong and the other three are okay.

Example 1. WRONG!

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

Example 2. RIGHT.

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

Example 3. RIGHT.

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

Example 4. RIGHT.

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

If you have a working program you should just be able to paste these snippets into your program and see that some compile and some do not.

Ivan
  • 4,383
  • 36
  • 27
0

I tried with gcc and come up with for my need I was forced to use the last alternative, to compile with out error.

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);
gg cg
  • 1
  • `new` is a bad choice of identifiers in the C family because its an operator in C++. – jww Sep 17 '17 at 06:31
0

C

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

Declaration which acts as a tentative definition of a signed integer s with complete type and declaration which acts as a tentative definition of signed integer q with incomplete type in the scope (which resolves to the complete type in the scope because the type definition is present anywhere in the scope) (like any tentative definition, the identifiers q and s can be redeclared with the incomplete or complete version of the same type int or enum stuff multiple times but only defined once in the scope i.e. int q = 3; and can only be redefined in a subscope, and only usable after the definition). Also you can only use the complete type of enum stuff once in the scope because it acts as a type definition.

A compiler enumeration type definition for enum stuff is also made present at file scope (usable before and below) as well as a forward type declaration (the type enum stuff can have multiple declarations but only one definition/completion in the scope and can be redefined in a subscope). It also acts as a compiler directive to substitute a with rvalue 0, b with -4, c with 5, d with -2, e with -3, f with -1 and g with -2 in the current scope. The enumeration constants now apply after the definition until the next redefinition in a different enum which cannot be on the same scope level.

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 

The tag namespace shared by enum, struct and union is separate and must be prefixed by the type keyword (enum, struct or union) in C i.e. after enum a {a} b, enum a c must be used and not a c. Because the tag namespace is separate to the identifier namespace, enum a {a} b is allowed but enum a {a, b} b is not because the constants are in the same namespace as the variable identifiers, the identifier namespace. typedef enum a {a,b} b is also not allowed because typedef-names are part of the identifier namespace.

The type of enum bool and the constants follow the following pattern in 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 |
+-----------+-----+---------------+------+

This compiles fine in 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++

In C++, enums can have a type

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

In this situation, the constants and the identifier all have the same type, bool, and an error will occur if a number cannot be represented by that type. Maybe = 2, which isn't a bool. Also, True, False and Bool cannot be lower case otherwise they will clash with language keywords. An enum also cannot have a pointer type.

The rules for enums are different in 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;
}

Enums variables in C++ are no longer just unsigned integers etc, they're also of enum type and can only be assigned constants in the enum. This can however be cast away.

#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
}

Enum classes

enum struct is identical to 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
}

The scope resolution operator can still be used for non-scoped enums.

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

But because w cannot be defined as something else in the scope, there is no difference between ::w and ::a::w

Community
  • 1
  • 1
Lewis Kelsey
  • 4,129
  • 1
  • 32
  • 42