The Shape of Everything
A website mostly about Mac stuff, written by Gus Mueller
» Acorn
» Retrobatch
» Twitter
» Micro.blog
» Mastodon
» Instagram
» Github
» Maybe Pizza?
» Archives
» Feed
» Micro feed
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)