Alternatives to type casting when formatting NS(U)Integer on 32 and 64 bit architectures? Alternatives to type casting when formatting NS(U)Integer on 32 and 64 bit architectures? ios ios

Alternatives to type casting when formatting NS(U)Integer on 32 and 64 bit architectures?


From http://pubs.opengroup.org/onlinepubs/009695399/functions/printf.html:

  • z
    Specifies that a following [...] conversion specifier applies to a size_t or the corresponding signed integer type argument;
  • t
    Specifies that a following [...] conversion specifier applies to a ptrdiff_t or the corresponding unsigned type argument;

And from http://en.wikipedia.org/wiki/Size_t#Size_and_pointer_difference_types:

  • size_t is used to represent the size of any object (including arrays) in the particular implementation. It is used as the return type of the sizeof operator.
  • ptrdiff_t is used to represent the difference between pointers.

On the current OS X and iOS platforms we have

typedef __SIZE_TYPE__ size_t;typedef __PTRDIFF_TYPE__ ptrdiff_t;

where __SIZE_TYPE__ and __PTRDIFF_TYPE__ are predefined by thecompiler. For 32-bit the compiler defines

#define __SIZE_TYPE__ long unsigned int#define __PTRDIFF_TYPE__ int

and for 64-bit the compiler defines

#define __SIZE_TYPE__ long unsigned int#define __PTRDIFF_TYPE__ long int

(This may have changed between Xcode versions. Motivated by @user102008's comment, I have checked this with Xcode 6.2 and updated the answer.)

So ptrdiff_t and NSInteger are both typedef'd to the same type:int on 32-bit and long on 64-bit. Therefore

NSLog(@"%td", i);NSLog(@"%tu", u);

work correctly and compile without warnings on all currentiOS and OS X platforms.

size_t and NSUInteger have the same size on all platforms, butthey are not the same type, so

NSLog(@"%zu", u);

actually gives a warning when compiling for 32-bit.

But this relation is not fixed in any standard (as far as I know), therefore I wouldnot consider it safe (in the same sense as assuming that long has the same sizeas a pointer is not considered safe). It might break in the future.

The only alternative to type casting that I know of is from the answer to "Foundation types when compiling for arm64 and 32-bit architecture", using preprocessor macros:

// In your prefix header or something#if __LP64__#define NSI "ld"#define NSU "lu"#else#define NSI "d"#define NSU "u"#endifNSLog(@"i=%"NSI, i);NSLog(@"u=%"NSU, u);


I prefer to just use an NSNumber instead:

NSInteger myInteger = 3;NSLog(@"%@", @(myInteger));

This does not work in all situations, but I've replaced most of my NS(U)Integer formatting with the above.


According to Building 32-bit Like 64-bit, another solution is to define the NS_BUILD_32_LIKE_64 macro, and then you can simply use the %ld and %lu specifiers with NSInteger and NSUInteger without casting and without warnings.