Заключение в бокс одного и того же члена перечисления выдает большее целое число, когда оно передается методу

Я использую примитив-боксерскую функцию Clang, чтобы упаковать член перечисления в NSNumber

Раздел Boxed Enums документа Clang об этом говорит, что компилятор помещает члены перечисления в целые числа, если тип не указан.

Как ни странно, я получаю целые числа разных размеров в зависимости от способа передачи члена перечисления методу. Я был в состоянии выделить случай до следующего кода

typedef enum _MyEnum {
    MyEnumMember1 = 1000
} MyEnum;

- (void)testEnumerationBoxing
{
    NSNumber *numberA = [self testA];
    NSNumber *numberB = [self testB:MyEnumMember1];

    CFNumberType numberTypeA = CFNumberGetType((__bridge CFNumberRef) numberA);
    CFNumberType numberTypeB = CFNumberGetType((__bridge CFNumberRef) numberB);
    NSLog(@"CF Number type for A: %lu; B: %lu", numberTypeA, numberTypeB);
}

- (NSNumber *)testA
{
    return @(MyEnumMember1);
}

- (NSNumber *)testB:(MyEnum)enumMember
{
    return @(enumMember);
}

Консольный вывод

Тип номера CF для A: 3; Б: 4

(первый kCFNumberSInt32Typeвторой kCFNumberSInt64Type)

Если я изменю декларацию на typedef enum _MyEnum : int Я вижу одинаковый результат для обоих: kCFNumberSInt32Type,

Почему размер целого числа отличается между двумя методами бокса?

2 ответа

Решение

Я считаю этот случай описанным в приведенной вами ссылке:

Упаковка значения типа enum приведет к появлению указателя NSNumber с методом создания в соответствии с базовым типом перечисления, который может быть фиксированным базовым типом или целочисленным типом, определяемым компилятором, который может представлять значения всех членов перечисление:

typedef enum : unsigned char { Red, Green, Blue } Color;
Color col => Red;
NSNumber *nsCol = @(col); // => [NSNumber numberWithUnsignedChar:]

но детали продвижения в библиотеках не рассматриваются, и именно здесь вводится разница в ожиданиях.

-testA в итоге звонит +[NSNumber numberWithInt:]

-testB в итоге звонит +[NSNumber numberWithUnsignedInt:]

Таким образом, абстрактное "продвижение" вы видите, потому что CFNumber (и следовательно NSNumber) на самом деле не поддерживают значения без знака в настоящее время (см. константы CFNumberType enums) - основываясь на выводе, который вы видите, можно предположить NSNumber Реализации просто переходят к следующему знаковому типу, способному представлять все значения в случае беззнакового инициализатора конструктора - очевидно, без проверки значения, чтобы увидеть, можно ли применить "минимизацию ширины".

Конечно, NSNumber объявляет конструкторы и инициализаторы, которые принимают беззнаковые типы в качестве параметров, но внутреннее представление целого числа без знака фактически сохраняется как целочисленное представление со знаком.

Компилятор, кажется, вызывает соответствующие / точные конструкторы удобства при продвижении упакованного литерала в NSNumber, Например, uint16_t типизированное перечисление будет сохранено как 32-битное целое (через numberWithUnsignedShort:), а int32_t также является 32-битным int (через numberWithInt:). Хотя, в случае -testA значение также известно, поэтому здесь также может быть вызван более подходящий конструктор, поэтому компилятор минимизирует ширину только на основе типа, а не типа и значения. если тип перечисления не указан или указан как тип без знака, вы можете увидеть подобные акции.

Проблема с константами перечисления (enum) заключается в том, что их типы данных часто не определены. Другими словами, константы перечисления не являются предсказуемо неподписанными int.

Посмотрите на http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Cocoa64BitGuide/64BitChangesCocoa/64BitChangesCocoa.html

Надеюсь, это поможет!

Другие вопросы по тегам