如何在C中定义枚举类型(枚举)?

时间:2009-07-09 08:29:02

标签: c enums

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

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

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

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

我做错了什么?

13 个答案:

答案 0 :(得分:444)

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

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

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

两种方式都有其优点和缺点。一个更罗嗦,但将类型标识符保留在tag-namespace中,它们不会与普通标识符冲突(考虑struct statstat函数:这些也不会发生冲突),你立刻就会发现它是一种类型。另一个更短,但将类型标识符带入普通命名空间。

答案 1 :(得分:362)

声明枚举变量的方式如下:

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;

答案 2 :(得分:55)

您尝试两次声明strategy,这就是您收到上述错误的原因。以下工作没有任何投诉(使用gcc -ansi -pendantic -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;
}

答案 3 :(得分:47)

当你说

enum {RANDOM, IMMEDIATE, SEARCH} strategy;

您创建了一个名为“无策略枚举”的“策略”的实例变量。这不是一件非常有用的事情 - 你需要一个typedef:

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

答案 4 :(得分:13)

如上所述,您的代码没有任何问题。你确定你没有做过像

这样的事吗
int strategy;
...
enum {RANDOM, IMMEDIATE, SEARCH} strategy;

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

答案 5 :(得分:11)

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

并具有相同的效果(即aaint且值为0

你也可以这样做:

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

aa将为int,其值为7

因为您不能使用enum重复符号常量定义,正如我之前所说,如果您想使用int声明enum变量,则必须使用标记:

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

答案 6 :(得分:10)

值得一提的是,在C ++ 中,您可以使用“enum”来定义新类型而无需typedef语句。

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

我发现这种方法更加友好。

[编辑 - 澄清了C ++状态 - 我最初有这个,然后将其删除!]

答案 7 :(得分:7)

关于宣言似乎存在混淆。

strategy出现在{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;

答案 8 :(得分:2)

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

如果未声明,则必须使用typedef

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

它不会显示错误...

答案 9 :(得分:2)

我最喜欢和唯一使用的建筑总是:

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

我相信这会消除你的问题。从我的观点来看,使用新类型是正确的选择。

答案 10 :(得分:1)

Tarc的答案是最好的。

enum讨论的大部分都是红鲱鱼。

比较此代码段: -

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

如果你有一个工作程序,你应该能够将这些片段粘贴到你的程序中,看看有些编译,有些则没有。

答案 11 :(得分:0)

我尝试使用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);

答案 12 :(得分:0)

C

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

该声明充当具有完整类型的带符号整数s的暂定定义,以及声明充当作用域中具有不完整类型的带符号整数q的暂定定义(解析为整数因为类型定义存在于范围中的任何地方,所以必须在范围内键入类型(与任何暂定定义一样,可以使用相同类型{{1的不完整或完整版本)来重新声明标识符qs }}或int多次,但只能在范围内定义一次,即int q = 3;并且只能在子范围内重新定义,并且只能在定义之后使用。另外,您只能在范围内使用一次完整的enum stuff类型,因为它充当类型定义。

enum stuff的编译器枚举类型定义也出现在文件范围(可在之前和之下使用)以及正向类型声明(类型enum stuff可以具有多个声明,但只有一个定义) / completion在范围内,可以在子范围内重新定义)。它也充当编译器指令,用右值enum stuff替换a,用0替换b,用-4,{{1}替换c }与5d-2e-3f-1在当前范围内。现在,枚举常量将在定义之后应用,直到在不同枚举中的下一个重新定义为止,而该枚举不能在同一作用域级别。

g

枚举,结构和联合共享的标签名称空间是分开的,并且必须在C中以类型关键字(枚举,结构或联合)作为前缀,即在-2之后必须使用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 a {a} b。因为标签名称空间与标识符名称空间是分开的,所以允许enum a c,但是a c不允许,因为常量与变量标识符标识符空间位于同一名称空间中。也不允许使用enum a {a} b,因为typedef名称是标识符名称空间的一部分。

enum a {a, b} b的类型和常量在C中遵循以下模式:

typedef enum a {a,b} b

这在C语言中可以正常编译:

enum bool

C ++

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

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

枚举的规则在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 ++中的枚举变量不再只是无符号整数等,它们还是枚举类型,只能在枚举中分配常量。但是,可以将其丢弃。

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

枚举类

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

范围解析运算符仍可用于非作用域枚举。

enum class

但是由于不能将w定义为范围中的其他内容,因此#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); } 之间没有区别