Why does an NSInteger variable have to be cast to long when used as a format argument?

You get this warning if you compile on OS X (64-bit), because on that platform NSInteger is defined as long and is a 64-bit integer. The %i format, on the other hand, is for int, which is 32-bit. So the format and the actual parameter do not match in size.

Since NSInteger is 32-bit or 64-bit, depending on the platform, the compiler recommends to add a cast to long generally.

Update: Since iOS 7 supports 64-bit now as well, you can get the same warning when compiling for iOS.


You don't have to cast to anything if your format specifiers match your data types. See Martin R's answer for details on how NSInteger is defined in terms of native types.

So for code intended to be built for 64-bit environments, you can write your log statements like this:

NSLog(@"%ld",  myInt); 

while for 32-bit environments you can write:

NSLog(@"%d",  myInt); 

and it will all work without casts.

One reason to use casts anyway is that good code tends to be ported across platforms, and if you cast your variables explicitly it will compile cleanly on both 32 and 64 bit:

NSLog(@"%ld",  (long)myInt);

And notice this is true not just for NSLog statements, which are just debugging aids after all, but also for [NSString stringWithFormat:] and the various derived messages, which are legitimate elements of production code.


Instead of passing an NSInteger to NSLog, just pass an NSNumber. This will get around all the casts and choosing the right string format specifier.

NSNumber foo = @9000;
NSLog(@"foo: %@", foo);
NSInteger bar = 9001;
NSLog(@"bar: %@", @(bar));

It also works for NSUIntegers without having to worry about that. See answer to NSInteger and NSUInteger in a mixed 64bit / 32bit environment