枚举值:NSInteger还是int?

Mic*_*Fey 39 cocoa enums typedef objective-c nsinteger

tl;博士版

在如此声明枚举时,枚举常量的数据类型如何保证为NSUInteger而不是unsigned int:

enum {
    NSNullCellType = 0,
    NSTextCellType = 1,
    NSImageCellType = 2
};
typedef NSUInteger NSCellType;
Run Code Online (Sandbox Code Playgroud)

NSUInteger的typedef似乎没有以任何方式绑定到枚举声明.

完整版本

我正在阅读Apple的64位Cocoa过渡指南,以获得有关枚举值的一些指导,我带来了一个问题.这是Enumeration Constants部分的一个(冗长的)引用,强调我的:

枚举(枚举)常量的一个问题是它们的数据类型经常是不确定的.换句话说,枚举常量不是可预测的unsigned int.对于传统构造的枚举,编译器实际上根据它找到的内容设置基础类型.底层类型可以是(signed)int或甚至long.请看以下示例:

type enum {
    MyFlagError = -1,
    MyFlagLow = 0,
    MyFlagMiddle = 1,
    MyFlagHigh = 2
} MyFlagType;
Run Code Online (Sandbox Code Playgroud)

编译器查看此声明,并查找分配给其中一个成员常量的负值,声明枚举int的基础类型.如果成员的值范围不适合int或unsigned int,则基类型将静默地变为64位(长整数).因此,定义为枚举的基本类型数量可以无提示地更改大小以符合枚举中的值.无论您是编译32位还是64位,都会发生这种情况.不用说,这种情况对二进制兼容性提出了障碍.

作为解决此问题的补救措施,Apple已决定更加明确Cocoa API中的枚举类型.现在,头文件不是根据枚举声明参数,而是单独声明可以指定大小的枚举类型.枚举的成员及其值将像以前一样声明和分配.例如,而不是这样:

typedef enum {
    NSNullCellType = 0,
    NSTextCellType = 1,
    NSImageCellType = 2
} NSCellType;
Run Code Online (Sandbox Code Playgroud)

现在有这个:

enum {
    NSNullCellType = 0,
    NSTextCellType = 1,
    NSImageCellType = 2
};
typedef NSUInteger NSCellType;
Run Code Online (Sandbox Code Playgroud)

枚举类型是根据NSInteger或NSUInteger定义的,以使基本枚举类型在64位体系结构上具有64位能力.

我的问题是:鉴于typedef似乎没有明确地与枚举声明绑定,如何知道他们的数据类型是unsigned int还是NSUInteger?

Cœu*_*œur 54

现在NS_ENUM开始Xcode 4.5:

typedef NS_ENUM(NSUInteger, NSCellType) {
    NSNullCellType = 0,
    NSTextCellType = 1,
    NSImageCellType = 2
};
Run Code Online (Sandbox Code Playgroud)

你可以考虑NS_OPTIONS使用二进制标志:

typedef NS_OPTIONS(NSUInteger, MyCellFlag) {
    MyTextCellFlag = 1 << 0,
    MyImageCellFlag = 1 << 1,
};
Run Code Online (Sandbox Code Playgroud)

  • 只需确保在执行此操作时,您不会在枚举中意外放置负值.它会导致Xcode在编译期间挂起而没有任何警告或错误.如果您从`enum`类型的`NSUInteger'开始然后决定要给它一个负值而忘记从类型中删除`U`,这很容易做到.希望这能节省一些时间. (2认同)

jav*_*gas 17

我在模拟器上运行测试,因此测试的目的是检查不同整数类型的大小.为此,结果sizeof打印在控制台中.所以我测试了这个enum值:

      
typedef enum {
    TLEnumCero = 0,
    TLEnumOne = 1,
    TLEnumTwo = 2
} TLEnum;

typedef enum {
    TLEnumNegativeMinusOne = -1,
    TLEnumNegativeCero = 0,
    TLEnumNegativeOne = 1,
    TLEnumNegativeTwo = 2
} TLEnumNegative;

typedef NS_ENUM(NSUInteger, TLUIntegerEnum) {
    TLUIntegerEnumZero = 0,
    TLUIntegerEnumOne = 1,
    TLUIntegerEnumTwo = 2
};

typedef NS_ENUM(NSInteger, TLIntegerEnum) {
    TLIntegerEnumMinusOne = -1,
    TLIntegerEnumZero = 0,
    TLIntegerEnumOne = 1,
    TLIntegerEnumTwo = 2
};
Run Code Online (Sandbox Code Playgroud)

测试代码:


    NSLog(@"sizeof enum: %ld", sizeof(TLEnum));
    NSLog(@"sizeof enum negative: %ld", sizeof(TLEnumNegative));
    NSLog(@"sizeof enum NSUInteger: %ld", sizeof(TLUIntegerEnum));
    NSLog(@"sizeof enum NSInteger: %ld", sizeof(TLIntegerEnum));
Run Code Online (Sandbox Code Playgroud)

结果对于iPhone的Retina(4英寸)的模拟器:


sizeof enum: 4
sizeof enum negative: 4
sizeof enum NSUInteger: 4
sizeof enum NSInteger: 4
Run Code Online (Sandbox Code Playgroud)

结果对于iPhone视网膜(4英寸64位)模拟器:


sizeof enum: 4
sizeof enum negative: 4
sizeof enum NSUInteger: 8
sizeof enum NSInteger: 8
Run Code Online (Sandbox Code Playgroud)

结论

泛型enum可以是32或64位的4个字节intunsigned int类型.正如我们已经知道的那样NSUInteger,NSInteger对于iOS,64位编译器中的32位和8字节是4个字节.


uli*_*ess 7

这是两个单独的声明.typedef保证,当您使用该类型时,您始终会获得NSUInteger.

枚举的问题并不在于它不足以容纳值.事实上,你得到枚举的唯一保证是sizeof(enum Foo)足够大,可以保存你目前在该枚举中定义的任何值.但是如果添加另一个常量,它的大小可能会改变.这就是为什么Apple做单独的typedef,以维持API的二进制稳定性.