如何定义一个枚举类型(enum)在C?

我不确定使用C枚举的正确语法是什么。我有以下代码:

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

但是这不能编译,会出现以下错误:

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

我做错了什么?

529055 次浏览

声明一个枚举变量是这样的:

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

然而,你可以使用typedef来缩短变量声明,如下所示:

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

有一个命名约定来区分类型和变量是一个好主意:

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

当你说

enum {RANDOM, IMMEDIATE, SEARCH} strategy;

创建一个名为“strategy”的实例变量。这不是一件非常有用的事情——你需要一个类型定义:

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

值得一提的是,在在c++中中,你可以使用“enum”来定义一个新类型,而不需要typedef语句。

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

我发现这种方法更友好。

[编辑-澄清c++状态-我原来有这个,然后删除它!]]

如前所述,您的代码没有任何问题。你确定你没做过类似的事吗

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

错误消息指向哪些行?当它说“以前的‘战略’宣言在这里”时,“这里”是什么?它显示了什么?

值得指出的是,你不会需要 typedef。你可以像下面这样做

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

这是一个风格问题,你是否喜欢typedef。如果没有它,如果你想引用枚举类型,你需要使用enum strategy。使用它,你可以只说strategy

两种方法都有优缺点。其中一种更冗长,但将类型标识符保留在标记命名空间中,在那里它们不会与普通标识符冲突(想想struct statstat函数:它们也不冲突),并且在那里您立即看到它是一个类型。另一个较短,但将类型标识符引入普通名称空间。

如果为枚举声明名称,则不会发生错误。

如果没有声明,则必须使用typedef:

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

它不会显示错误…

你试图声明strategy两次,这就是你得到上述错误的原因。以下工作没有任何抱怨(由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;
}

如果将第二行改为:

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

从警告中,你可以很容易地发现你的错误:

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

因此,编译器将strategy = IMMEDIATE作为一个名为strategy的变量的声明,该变量的默认类型为int,但之前已经有一个具有此名称的变量的声明。

然而,如果你将赋值放在main()函数中,它将是一个有效的代码:

#include <stdio.h>


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


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


return 0;
}
@ThoAppelsin在他对问题的评论中是正确的。问题中发布的代码片段是有效的,没有错误。这个错误一定是因为c源文件的其他地方有错误的语法。enum{a,b,c};定义了三个符号常量(abc),它们分别是值为012的整数,但当我们使用enum时,这是因为我们通常不关心具体的整数值,我们更关心符号常量名称的含义。 这意味着你可以得到:

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

这将输出1

这也是有效的:

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

并将输出与之前相同的结果。

如果你这样做:

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

你会有一个错误,但是如果你这样做:

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

你不会有任何错误。

你可以这样做:

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

aa将是一个值为0的整型变量。但你也可以这样做:

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

并具有相同的效果(即,aa是具有0值的int)。

你还可以这样做:

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

aa将是int,值为7

因为你不能使用enum来重复符号常量定义,就像我之前说过的,如果你想使用enum来声明int变量,你必须使用标签:

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

typedef的使用是为了避免你每次都写enum tag1来定义变量。对于typedef,你可以输入Tag1:

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

你还可以有:

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

最后要说的是,由于我们谈论的是已定义的符号常量,所以在使用enum时最好使用大写字母,例如:

enum {A,B,C};

而不是

enum {a,b,c};

这份声明似乎有些混乱。

当__abc0出现在{RANDOM, IMMEDIATE, SEARCH}之前,如下所示,

enum strategy {RANDOM, IMMEDIATE, SEARCH};

你正在创建一个名为enum strategy的新类型。然而,在声明变量时,你需要使用enum strategy本身。你不能只使用strategy。所以下面的内容无效。

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

但是,以下是有效的

enum strategy {RANDOM, IMMEDIATE, SEARCH};


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

strategy出现在{RANDOM, IMMEDIATE, SEARCH}之后,你创建了一个匿名枚举,然后声明strategy为该类型的变量。

现在,你可以这样做

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

然而,你不能声明任何其他类型的enum {RANDOM, IMMEDIATE, SEARCH}变量,因为你从来没有命名过它。所以下面的内容无效

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

你也可以把这两个定义结合起来

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


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

如前所述,Typedef用于创建一个更短的变量声明。

typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy;

现在你已经告诉编译器enum {RANDOM, IMMEDIATE, SEARCH}strategy的同义词。所以现在你可以自由地使用strategy作为变量类型。你不再需要输入enum strategy。以下是现在有效的

strategy x = RANDOM;

你也可以结合Typedef和枚举名称来获取

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

除了现在可以互换使用strategyenum strategyName之外,使用这个方法并没有太多的好处。

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


enum strategyName a = RANDOM;
strategy b = SEARCH;

我尝试了gcc,并提出了我的需要,我被迫使用最后一种选择,编译出来的错误。

typedef enum 状态 {a = 0, b = 1, c = 2} 状态;

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

Tarc的答案是最好的。

全会的许多讨论都是在转移话题。

比较以下代码片段:-

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

这给了

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

用这个编译没有问题。

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

变量strategy需要在声明中或在函数中设置。您不能在全局范围内编写任意软件——特别是赋值软件。

他使用enum {RANDOM, IMMEDIATE, SEARCH}而不是int这一事实只与它使那些无法超越它的人感到困惑有关。 问题中的重定义错误消息表明这是作者所做的错误

现在你应该可以看出为什么下面的第一个例子是错误的,而其他三个例子是正确的。

例1。错了!

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

例2。正确的。

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

例3。正确的。

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

例4。正确的。

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

如果你有一个工作的程序,你应该能够将这些代码段粘贴到你的程序中,并看到一些编译和一些不编译。

我最喜欢和唯一使用的结构是:

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

我相信这会解决你的问题。在我看来,使用新字体是正确的选择。

C

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

作为有符号整型s的临时定义的声明,具有完整类型;作为有符号整型q的临时定义的声明,作用域内具有不完整类型(它在作用域内解析为完整类型,因为类型定义出现在作用域的任何位置)(就像任何临时定义一样,标识符qs可以多次用相同类型intenum stuff的不完整或完整版本重新声明,但只能在作用域中定义一次,即int q = 3;并且只能在子作用域内重新定义,并且只能在定义后使用)。此外,在作用域中只能使用一次enum stuff的完整类型,因为它充当类型定义。

enum stuff的编译器枚举类型定义也出现在文件作用域(前面和下面可用)以及正向类型声明(类型enum stuff可以有多个声明,但在作用域中只能有一个定义/补全,并且可以在子作用域中重新定义)。它还充当编译器指令,在当前作用域中用右值0替换a,用-4替换b,用5替换c,用-2替换d,用enum stuff1替换enum stuff0,用enum stuff3替换enum stuff2,用-2替换enum stuff4。枚举常量现在应用于定义之后,直到下一次在不同的枚举中重新定义,该枚举不能在同一作用域级别上。

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

由enum、struct和union共享的标签命名空间是分开的,在C语言中必须以类型关键字(enum、struct或union)作为前缀,即在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语言中遵循以下模式:

+--------------+-----+-----+-----+
|   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 |
+-----------+-----+---------------+------+


这在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++

在c++中,枚举可以有类型

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

在这种情况下,常量和标识符都具有相同的类型bool,如果一个数字不能用该类型表示,就会发生错误。也许= 2,这不是bool类型。此外,True、False和Bool不能小写,否则它们将与语言关键字冲突。枚举也不能有指针类型。

在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;
}

c++中的enum变量不再只是无符号整数等,它们也是enum类型,只能在enum中赋值常量。然而,这是可以抛弃的。

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

范围解析操作符仍然可以用于非范围枚举。

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

但是因为w不能被定义为作用域中的其他东西,所以::w::a::w之间没有区别