Boxing the same member of the enumeration produces a larger integer when it is passed to the method

I use the Clang primitive boxing function to pack an enumeration member into NSNumber

The section in the Forwarding Boxes section of the Clang document says that the enumerated compiler elements are listed in integers, unless that type is specified.

Oddly enough, I get different sizes of integers depending on how I pass the enumeration member to the method. I was able to isolate the case until the following code

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

Console output

CF number type for A: 3; B: 4

(the first is kCFNumberSInt32Type , the second is kCFNumberSInt64Type )

If I change the declaration to typedef enum _MyEnum : int , I see the same result for both: kCFNumberSInt32Type .

Why is the size of the whole different from the two boxing methods?

+7
source share
2 answers

I consider this case as described in the link provided:

Boxing: an enumeration type value will lead to an NSNumber pointer with a creation method according to the base enumeration type, which can be a fixed base type or an integer specified by the compiler capable of representing the values ​​of all members of the enumeration:

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

but the details of advertising campaigns in libraries are not considered, and that is where the difference in expectations is introduced.

-testA ends with a call to +[NSNumber numberWithInt:]

-testB ends with a call to +[NSNumber numberWithUnsignedInt:]

So the abstracted β€œpromotion” you see is due to the fact that CFNumber (and therefore NSNumber ) does not actually support unsigned values ​​at this time (see the CFNumberType enumeration constants) - based on the output you see, then it could be assumed that NSNumber implementations NSNumber simply advancing to the next signed type, capable of representing all values ​​in the case of an unsigned constructor initializer - apparently without checking the value to see if any "width minimization" can be applied.

Of course, NSNumber declares constructors and initializers that accept unsigned types as parameters, but the internal representation of an unsigned integer is actually stored as a signed integer.

The compiler apparently calls the appropriate / exact convenience constructors when pushing the string literal to NSNumber . For example, a typed enum uint16_t will be saved as a 32-bit int (via numberWithUnsignedShort: , and int32_t is also a 32-bit int (via numberWithInt: . Although in the case of -testA value is also known, therefore a more suitable constructor can also be called here, therefore the compiler only minimizes the width based on the type, and not the type and value. when an enumeration type is not specified or indicated as an unsigned type, you can see such promotions.

+4
source

The problem with enum constants is that their data types are often undefined. In other words, enumeration constants are not predictable unsigned ints.

Take a look at http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Cocoa64BitGuide/64BitChangesCocoa/64BitChangesCocoa.html

Hope this helps!

+1
source

All Articles