枚举值:NSInteger或int?

tl; dr版本

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

enum {
    NSNullCellType = 0,
    NSTextCellType = 1,
    NSImageCellType = 2
};
typedef NSUInteger NSCellType;

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

完整版

我正在阅读Apple的Cocoa 64位过渡指南,以获取关于枚举值的一些指导,并且我提出了一个问题。 下面是枚举常量部分的一段(冗长)引用,重点是我的:

枚举(enum)常量的一个问题是它们的数据类型通常是不确定的。 换句话说,枚举常量不是可预测的unsigned int。 使用传统构造的枚举,编译器实际上会根据找到的内容设置基础类型。 基础类型可以是(签名)int或甚至更长。 以下面的例子:

type enum {
    MyFlagError = -1,
    MyFlagLow = 0,
    MyFlagMiddle = 1,
    MyFlagHigh = 2
} MyFlagType;

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

作为解决这个问题的一种补救方法,Apple决定在Cocoa API中更加明确地列举枚举类型。 而不是根据枚举声明参数,头文件现在单独声明枚举的类型,该枚举的大小可以被指定。 列举的成员及其价值与以前一样被宣布和分配。 例如,而不是这个:

typedef enum {
    NSNullCellType = 0,
    NSTextCellType = 1,
    NSImageCellType = 2
} NSCellType;

现在有这个:

enum {
    NSNullCellType = 0,
    NSTextCellType = 1,
    NSImageCellType = 2
};
typedef NSUInteger NSCellType;

枚举类型根据NSInteger或NSUInteger进行定义,以便在64位体系结构上支持64位的基本枚举类型。

我的问题是这样的:鉴于typedef看起来并不明确地绑定到枚举声明,如何知道它们的数据类型是无符号整型还是NSUInteger?


现在NS_ENUM启动Xcode 4.5的NS_ENUM

typedef NS_ENUM(NSUInteger, NSCellType) {
    NSNullCellType = 0,
    NSTextCellType = 1,
    NSImageCellType = 2
};

如果你使用二进制标志,你可以考虑使用NS_OPTIONS

typedef NS_OPTIONS(NSUInteger, MyCellFlag) {
    MyTextCellFlag = 1 << 0,
    MyImageCellFlag = 1 << 1,
};

我在模拟器上运行测试,因此测试的目的是检查不同整数类型的大小。 为此, 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
};

测试代码:


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

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


sizeof enum: 4
sizeof enum negative: 4
sizeof enum NSUInteger: 4
sizeof enum NSInteger: 4

iPhone Retina(4英寸64位)模拟器的结果


sizeof enum: 4
sizeof enum negative: 4
sizeof enum NSUInteger: 8
sizeof enum NSInteger: 8

结论

泛型enum可以是32或64位的4字节的intunsigned int类型。 由于我们已经知道NSUIntegerNSInteger是4个字节用于32位和64位的编译器为iOS 8个字节。


这是两个单独的声明。 typedef保证,当你使用这种类型时,你总会得到一个NSUInteger。

枚举的问题并不在于它不足以保存值。 实际上,您为枚举获得的唯一保证是sizeof(枚举Foo)足够大,以容纳您当前在该枚举中定义的任何值。 但是如果添加另一个常量,其大小可能会改变。 这就是为什么苹果为了维护API的二进制稳定性而做独立的typedef。

链接地址: http://www.djcxy.com/p/57435.html

上一篇: enum values: NSInteger or int?

下一篇: Push notifications from linux for iOS apps via SSL with PHP