Подтвердить что ты не робот

Значения перечисления: NSInteger или int?

tl; dr Версия

Как типы данных констант перечисления гарантированно являются NSUInteger вместо unsigned int при объявлении перечисления таким образом:

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

typedef для NSUInteger никак не привязывается к объявлению перечисления.

Полная версия

Я читал через Apple 64-битное руководство по переходу для Cocoa для некоторых рекомендаций по значениям перечисления, и я ушел с вопрос. Здесь (длинная) цитата из раздела Enumeration Constants, основное внимание:

Проблема с константами перечисления (enum) заключается в том, что их типы данных часто являются неопределенными. Другими словами, константы континуума не являются предсказуемыми беззнаковыми int.. С условно сконструированными перечислениями компилятор фактически устанавливает базовый тип в зависимости от того, что он находит. Основной тип может быть (подписан) int или даже длинным. Возьмем следующий пример:

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

Компилятор просматривает это объявление и, обнаруживая отрицательное значение, назначенное одной из констант-членов, объявляет базовый тип перечисления int. Если диапазон значений для членов не вписывается в int или unsigned int, тогда базовый тип становится 64-битным (длинным). Таким образом, базовый тип величин, определяемый как перечисления, может изменять молчащий размер, чтобы соответствовать значениям в перечислении. Это может произойти, если вы компилируете 32-разрядные или 64-разрядные. Излишне говорить, что эта ситуация создает препятствия для совместимости двоичных файлов.

В качестве средства для решения этой проблемы Apple решила более подробно описать тип перечисления в API Cocoa. Вместо объявления аргументов в терминах перечисления файлы заголовков теперь отдельно объявить тип для перечисления, размер которого можно указать. Члены перечисления и их значения объявляются и назначаются по-прежнему. Например, вместо этого:

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

теперь есть следующее:

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

Тип перечисления определяется в терминах NSInteger или NSUInteger, чтобы сделать базовый тип перечисления 64-разрядным для 64-разрядных архитектур.

Мой вопрос заключается в следующем: учитывая, что typedef явно не привязан явно к объявлению enum, как узнать, являются ли их типы данных неподписанными int или NSUInteger?

4b9b3361

Ответ 1

Теперь существует NS_ENUM запуск Xcode 4.5:

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

И вы можете рассмотреть NS_OPTIONS, если вы работаете с двоичными флагами:

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

Ответ 2

Я запускаю тест на симуляторе, поэтому целью теста является проверка размера разных целых типов. Для этого результат 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-inch) Simulator:


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 может быть int или unsigned int типами 4 байта для 32 или 64 бит. Как мы уже знаем, NSUInteger и NSInteger составляют 4 байта для 32 бит и 8 байтов в 64-битном компиляторе для iOS.

Ответ 3

Это два отдельных объявления. Typedef гарантирует, что при использовании этого типа вы всегда получаете NSUInteger.

Проблема с перечислением заключается не в том, что он недостаточно велик, чтобы удерживать значение. Фактически, единственная гарантия, которую вы получаете для перечисления, заключается в том, что sizeof (enum Foo) достаточно велик, чтобы удерживать все значения, которые вы в настоящее время определили в этом перечислении. Но его размер может измениться, если вы добавите еще одну константу. Вот почему Apple делает отдельный typedef, чтобы поддерживать бинарную стабильность API.

Ответ 4

Типы данных констант перечисления не гарантируются NSUInteger, но они гарантированно будут отбрасываться до NSUInteger каждый раз, когда вы используете их через NSCellType.

Другими словами, в декларации указывается, что, хотя значения перечисления в настоящее время будут вписываться в unsigned int, зарезервированное для них хранилище при доступе через NSCellType должно быть NSUInteger.