在C ++中声明枚举时,为什么要使用typedef?


183

多年以来我都没有写过任何C ++,现在我正尝试重新使用它。然后,我遇到了这个问题,并考虑放弃:

typedef enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

这是什么?为什么在typedef这里使用关键字?为什么名称TokenType在此声明中出现两次?语义与此有何不同:

enum TokenType
{
    blah1 = 0x00000000,
    blah2=0x01000000,
    blah3=0x02000000
};

Answers:


156

在C语言中,以第一种方式声明枚举可让您像这样使用它:

TokenType my_type;

如果您使用第二种样式,则将被迫这样声明变量:

enum TokenType my_type;

正如其他人所提到的,这在C ++中没有任何区别。我的猜测是,编写此代码的人本质上是C程序员,或者您正在将C代码编译为C ++。无论哪种方式,它都不会影响代码的行为。


12
您的问题仅对C正确,而对C ++不正确。在C ++中,可以像使用typedef一样直接使用枚举和结构。
大卫·罗德里格斯(DavidRodríguez)-德里贝斯

7
好吧,是的,但这确实回答了真正的问题,即“这到底意味着什么?”。
BobbyShaftoe

那么这在技术上是typedef还是枚举?
米耶克(Miek)2012年

5
都是。您也可以说:枚举TokenType_ {...}; typedef枚举TokenType_ TokenType;
瑞安·福克斯

答案是完整的,但我认为重点是TokenType;枚举声明之后是声明类型名称的内容。因此答案不是100%完整的。声明“第一种方式”同时指定了一个枚举和一个新的类型名,即一个语法中的那个枚举。因此答案很有帮助,但我认为可以有所改善。也许我太苛刻了,不能拒绝投票。所以我全力以赴。如果我真的很确定自己,我会花些时间编辑/改善答案...但这是一个很好的答案
Ross Youngblood

97

如果您这样做的话,这是C的C遗产:

enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
};

您必须使用它来执行以下操作:

enum TokenType foo;

但是,如果您这样做:

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

您将可以声明:

TokenType foo;

但是在C ++中,您只能使用以前的定义,并且就像在C typedef中一样使用它。


1
您所说的在C中是正确的。在C ++中不是正确的。
乔纳森·莱夫勒

49
我的最后一句话不是吗?

2
@mat我赞成您对最后一句话的评论,但为公平起见,它的措辞不佳且令人困惑。
2014年

20

您不需要这样做。在C(不是C ++)中,您需要使用枚举Enumname来引用枚举类型的数据元素。为了简化它,你被允许的typedef它一个名称的数据类型。

typedef enum MyEnum { 
  //...
} MyEnum;

允许将带有枚举参数的函数定义为

void f( MyEnum x )

而不是更长

void f( enum MyEnum x )

请注意,typename的名称不必等于枚举的名称。结构也是如此。

另一方面,在C ++中则不需要,因为枚举,类和结构可以通过名称直接作为类型进行访问。

// C++
enum MyEnum {
   // ...
};
void f( MyEnum x ); // Correct C++, Error in C

实际上,我认为这可能是比公认的更好的答案,因为它清楚地说明了“为什么”不同。
Ross Youngblood

11

在C语言中,这是一种很好的样式,因为您可以将类型更改为枚举以外的其他类型。

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

foo(enum e_TokenType token);  /* this can only be passed as an enum */

foo(TokenType token); /* TokenType can be defined to something else later
                         without changing this declaration */

在C ++中,您可以定义枚举,以便将其编译为C ++或C。


您不是要说In C++ you can *typedef* the enum so that it will compile as C++ or C.吗?您说:In C++ you can define the enum so that it will compile as C++ or C.请注意我如何将您更改definetypedef。嗯......我想typedef荷兰国际集团定义。
加布里埃尔·斯台普斯

6

C的保留


邓诺(Dunno)认为“早期”限定词是相关的;如果您想使用不带枚举前缀的类型名称,仍然会用C编写该代码。
乔纳森·莱夫勒

1
真正。我将其删除。我已经很长时间没有遵循C规范了。我懒得检查c / c ++的区别... -1对我而言。
Tim

6

有人说C没有命名空间,但是从技术上讲这是不正确的。它具有三个:

  1. 标签(enumunion,和struct
  2. 标签
  3. (其他)

typedef enum { } XYZ;声明一个匿名枚举,并将其导入名称为的全局命名空间XYZ

typedef enum ABC { } XYZ;ABC在标签名称空间中声明一个名为enum的枚举,然后将其导入到全局名称空间中XYZ

有些人不想打扰单独的命名空间,因此他们对所有内容进行类型定义。其他人从来没有键入def,因为他们想要命名空间。


这并不完全正确。标记名称引用了结构,联合和枚举(除非您提到匿名,否则除外)。类型和标签有单独的命名空间。您可以使用与标签名称完全相同的类型,然后进行编译。但是,如果枚举与结构具有相同的标记,则这是一个编译错误,与2个具有相同标记的结构或2个枚举完全相同。您还忘记了goto的标签是一个单独的命名空间。标签可以是与标签相同的名称,也可以是标识符,但不能是类型,并且标识符可以与标签具有相同的名称,但不能是类型。
Rich Jahn

3

这有点旧,但是无论如何,我希望您会喜欢我今年年初遇到的链接,因为我会喜欢它。

这里。当我必须掌握一些讨厌的typedef时,我应该引用我心中永远存在的解释:

在变量声明中,引入的名称是相应类型的实例。[...]但是,当typedef关键字在声明之前时,引入的名称是相应类型的别名

就像许多人以前说过的那样,无需使用C ++中声明枚举的typedefs 。但这就是对typedef语法的解释!我希望它能对您有所帮助(由于已经使用了将近10年,所以可能不是OP,但是任何人都在努力理解此类事情)。


1

在某些C代码风格指南中,typedef版本被称为“声明”和“简洁”的首选。我不同意,因为typedef混淆了声明对象的真实本质。实际上,我不使用typedef,因为在声明C变量时,我想弄清楚对象的实际含义。这种选择可以帮助我更快地记住旧代码的实际作用,并在将来维护代码时帮助其他人。


1

“为什么”问题的实际答案(这个老问题之前的现有答案令人惊讶地忽略了该问题)是该enum声明可能位于标头文件中,该标头文件旨在作为C和C ++代码进行交叉编译(即包含在C和C ++实现文件中)。编写此类头文件的技巧取决于作者选择在两种语言中具有适当兼容含义的语言功能的能力。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.