значения enum: NSInteger или int? - PullRequest
39 голосов
/ 14 декабря 2011

tl; dr Версия

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

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

typedef для NSUInteger делаетпохоже, никак не связаны с объявлением enum.

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

Я читал 64-битное руководство Apple по переходу для какао для некоторого руководства по значениям перечисления, и я ушел с вопросом.Вот (длинная) цитата из раздела Константы перечисления , выделение мое:

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

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,как узнать, что их типы данных - unsigned int или NSUInteger?

Ответы [ 4 ]

54 голосов
/ 13 ноября 2012

Теперь 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,
};
17 голосов
/ 07 января 2014

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

7 голосов
/ 14 декабря 2011

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

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

2 голосов
/ 14 декабря 2011

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

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

...