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 r-value 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 |
+-----------+-----+---------------+------+
Which shows that the constant type is based on the literal assigned to it, and integer literals without a suffix always customarily follow int > long int > long long int (and a character literal is also an int in C, but not C++). The enum type, however, appears to be the smallest type that can represent all constants defined in the enum (and prefers to choose unsigned int when all the integers are positive, for whatever reason).
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. A forward declaration of enum
// type is 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 it is 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 isn't any difference between ::w and ::a::w.
strategyas 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 trivialmain()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.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.enum strategy { ... };defines an enumerated type namedenum strategy, wherestrategyis the tag.enum { ... } strategy;defines an anonymous enumerated type (no tag) and a single object of that type namedstrategy. Both are perfectly legal; they just mean different things.