提问



我不认为我从根本上理解enum是什么,以及何时使用它。


例如:


typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;


这里真的被宣布了什么?

最佳参考


这里声明了三件事:声明了匿名枚举类型,ShapeType被声明为匿名枚举的typedef,以及三个名称kCirclekRectanglekOblateSpheroid被宣布为整数常数。


让我们打破它。在最简单的情况下,枚举可以声明为


enum tagname { ... };


这声明了带有标签tagname的枚举。在C和Objective-C(但不 C ++)中,对此的任何引用都必须以enum关键字开头。例如:


enum tagname x;  // declare x of type 'enum tagname'
tagname x;  // ERROR in C/Objective-C, OK in C++


为了避免在任何地方使用enum关键字,可以创建一个typedef:


enum tagname { ... };
typedef enum tagname tagname;  // declare 'tagname' as a typedef for 'enum tagname'


这可以简化为一行:


typedef enum tagname { ... } tagname;  // declare both 'enum tagname' and 'tagname'


最后,如果我们不需要能够enum tagname使用enum关键字,我们可以使enum匿名,只使用typedef名称声明它:


typedef enum { ... } tagname;


现在,在这种情况下,我们声明ShapeType是匿名枚举的typedef名称。 ShapeType实际上只是一个整数类型,并且只应用于声明包含声明中列出的值之一的变量(即kCirclekRectangle和[[之一]] kOblateSpheroid)。但是,您可以通过强制转换为ShapeType变量指定另一个值,因此在读取枚举值时必须小心。


最后,kCirclekRectanglekOblateSpheroid被声明为全局命名空间中的整数常量。由于未指定特定值,因此将它们分配给以0开头的连续整数,因此kCircle为0,kRectangle为1,kOblateSpheroid为2。

其它参考1


Apple建议从Xcode 4.4开始定义这样的枚举:


typedef enum ShapeType : NSUInteger {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;


它们还提供了一个方便的宏NS_ENUM:


typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};


这些定义提供更强的类型检查和更好的代码完成。我找不到NS_ENUM的官方文档,但您可以在这里观看WWDC 2012会议的Modern Objective-C视频。[62]


更新:链接到官方文档。[63]

其它参考2


枚举声明了一组有序值 - typedef只是为此添加了一个方便的名称。第一个元素是0等


typedef enum {
Monday=1,
...
} WORKDAYS;

WORKDAYS today = Monday;


以上只是shapeType标签的枚举。

其它参考3


用户定义的类型,其可能值为kCirclekRectanglekOblateSpheroid。但是,enum(kCircle等)中的值在枚举之外是可见的。记住这一点很重要(例如,int i = kCircle;是有效的)。

其它参考4


更新64位更改:
根据关于64位变化的苹果文档,[64]



  枚举也是类型的:在LLVM编译器中,枚举类型可以
  定义枚举的大小。这意味着有些枚举
  类型的大小也可能比您预期的大。该
  与所有其他情况一样,解决方案是不做任何关于a的假设
  数据类型的大小。而是将任何枚举值分配给变量
  使用正确的数据类型



因此,如果您支持64位,则必须使用类型创建枚举,如下面的语法。


typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};


要么


typedef enum ShapeType : NSUInteger {
   kCircle,
   kRectangle,
   kOblateSpheroid
} ShapeType;


否则,它将导致警告Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType


swift-programming更新:


在swift中,语法发生了变化。


enum ControlButtonID: NSUInteger {
        case kCircle , kRectangle, kOblateSpheroid
    }

其它参考5


枚举是用户定义的数据类型。
已记录的数据类型
枚举数据类型变量只能采用先前声明的值。


enum month { jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec };
enum month this_month;

this_month = feb;


在上面的声明中,month声明为枚举数据类型。它由一组值组成,jan到dec。在数值上,jan的值为1,feb的值为2,依此类推。


变量this_month被声明为与month相同的类型,然后被赋予与feb相关联的值。无法为this_month指定在月份声明的初始化列表中指定的值之外的任何值。

其它参考6


枚举(枚举的缩写)用于枚举一组值(枚举器)。值是由符号(单词)表示的任何抽象事物。
例如,基本枚举可以是


enum { xs,s,m,l,xl,xxl,xxxl,xxxxl };


此枚举称为匿名,因为您没有用于命名它的符号。但它仍然是完全正确的。就这样使用它


enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;


好。生活很美好,一切顺利。但有一天你需要重用这个枚举来定义一个新的变量来存储myGrandFatherPantSize,然后你写:


enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandFatherPantSize;


但是你有一个编译器错误重新定义枚举器。实际上问题是编译器不确定你是第一次枚举而你的第二次描述同样的事情。


然后,如果要在多个位置重用同一组枚举器(此处为xs ... xxxxl),则必须使用唯一名称对其进行标记。第二次使用此设置时,您只需使用标记。但是不要忘记这个标签不会取代枚举词,而只会取代枚举器的集合。然后像往常一样注意使用枚举。像这样:


// Here the first use of my enum
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize; 
// here the second use of my enum. It works now !
enum sizes myGrandFatherPantSize;


您也可以在参数定义中使用它:


// Observe that here, I still use the enum
- (void) buyANewDressToMyGrandMother:(enum sizes)theSize;


你可以说在任何地方重写枚举都不方便,并使代码看起来有点奇怪。你是对的。真正的类型会更好。


这是我们进入峰会的最后一步。通过添加一个typedef,我们可以将我们的枚举转换成一个真正的类型。哦,最后一件事,你的类中不允许使用typedef。然后在上面定义你的类型。这样做:


// enum definition
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl };
typedef enum sizes size_type

@interface myClass {
   ...
   size_type myGrandMotherDressSize, myGrandFatherPantSize;
   ...
}


请记住,标签是可选的。然后,在这种情况下,我们不会标记枚举器,只是为了定义一个新类型。那我们就不再需要了。


// enum definition
typedef enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } size_type;

@interface myClass : NSObject {
  ...
  size_type myGrandMotherDressSize, myGrandFatherPantSize;
  ...
}
@end


如果您使用XCode在ObjectiveC中进行开发,我将让您发现一些以NS_ENUM为前缀的漂亮宏。这应该可以帮助您轻松定义好的枚举,而且还有助于静态分析器在编译之前为您做一些有趣的检查。


好恩生!

其它参考7


typedef对于重新定义现有变量类型的名称很有用。它提供简短的&调用数据类型的有意义的方法。
例如:


typedef unsigned long int TWOWORDS;


这里,unsigned long int类型被重新定义为TWOWORDS类型。因此,我们现在可以通过写入声明unsigned long int类型的变量,


TWOWORDS var1, var2;


代替


unsigned long int var1, var2;

其它参考8


typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;


然后你就可以使用它: -


 ShapeType shape;





 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} 
ShapeType;


现在你可以像以下一样使用它: -


enum ShapeType shape;

其它参考9


枚举用于为枚举元素赋值,这些元素无法在struct中完成。因此,每次都可以通过我们分配给枚举中的变量的值来代替访问完整变量。默认情况下,它以0赋值开始,但我们可以为其赋值任何值,枚举中的下一个变量将被赋值为前一个值+1。

其它参考10


typedef允许程序员将一个Objective-C类型定义为另一个。例如,


typedef int Counter;将类型Counter定义为等效于int类型。这大大提高了代码的可读性。

其它参考11


Typedef是C和C ++中的关键字。它用于为基本数据类型(char,int,float,double,struct& enum)创建新名称。


typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;


在这里,它创建枚举数据类型 ShapeType &我们可以为枚举类型 ShapeType 编写新名称,如下所示


ShapeType shape1; 
ShapeType shape2; 
ShapeType shape3;

其它参考12


您可以使用以下格式,Raw默认值从0开始,所以



  • kCircle是0,

  • kRectangle是1,

  • kOblateSpheroid是2。



您可以指定自己的特定起始值。


typedef enum : NSUInteger {
    kCircle, // for your value; kCircle = 5, ...
    kRectangle,
    kOblateSpheroid
} ShapeType;

ShapeType circleShape = kCircle;
NSLog(@"%lu", (unsigned long) circleShape); // prints: 0

其它参考13


枚举可以减少许多类型的错误并使代码更易于管理


#define STATE_GOOD 0
#define STATE_BAD 1
#define STATE_OTHER 2
int STATE = STATE_OTHER


该定义没有约束。它只是一个替代品。
它无法限制州的所有条件。当STATE分配给5时,程序将是错误的,因为没有匹配状态。但是编译器不会警告STATE=5


所以最好这样使用


typedef enum SampleState {
    SampleStateGood  = 0,
    SampleStateBad,
    SampleStateOther
} SampleState;

SampleState state = SampleStateGood;