September 14, 2018
I've been working on new JavaScript to C/Cocoa bridge lately, for fun and education. And I made an interesting discovery today- NSNumber stores shorts and unsigned chars the same. Is this a bug in NSNumber? Consider the following code:
printf("@encode(short) %s, %s, %c, %lu\n",
@encode(short),
[[NSNumber numberWithShort:'a'] objCType],
_C_SHT,
sizeof(short));
printf("@encode(char) %s, %s, %c, %lu\n",
@encode(char),
[[NSNumber numberWithChar:'a'] objCType],
_C_CHR,
sizeof(char));
printf("@encode(unsigned char) %s, %s, %c, %lu\n",
@encode(unsigned char),
[[NSNumber numberWithUnsignedChar:'a'] objCType],
_C_UCHR,
sizeof(unsigned char));
Outputs:
@encode(short) s, s, s, 2
@encode(char) c, c, c, 1
@encode(unsigned char) C, s, C, 1
I'd love to update this post if anyone has any ideas why this happens.
OK here's that update:
NSNumber is most likely built on top of CFNumber. And CFNumber doesn't support unsigned char- so it bumps the storage up to a signed short (from 8 bits to 16) in order to keep from rounding over. The same thing occurs for unsigned int:
printf("@encode(int) %s, %s, %c, %lu\n",
@encode(int),
[[NSNumber numberWithInt:1] objCType],
_C_INT,
sizeof(int));
printf("@encode(unsigned int) %s, %s, %c, %lu\n",
@encode(unsigned int),
[[NSNumber numberWithUnsignedInt:1] objCType],
_C_UINT,
sizeof(unsigned int));
printf("@encode(long long) %s, %s, %c, %lu\n",
@encode(long long),
[[NSNumber numberWithLongLong:1] objCType],
_C_LNG_LNG,
sizeof(long long));
Outputs:
@encode(int) i, i, i, 4
@encode(unsigned int) I, q, I, 4
@encode(long long) q, q, q, 8
Why long long and not long? Because on 64 bit sizeof(long)
is the same as sizeof(long long)