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

NSInteger myInt = 1804809223;
NSLog(@"%i", myInt); <==== 

The code above produces an error:

Values of type "NSInteger" should not be used as format arguments: add an explicit cast to 'long' instead.

The correct NSLog message is actually NSLog(@"%lg", (long) myInt); Why do I have to convert the integer value of myInt to long if I want the value to display?

Answers


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 which native types NSInteger is defined as.

So on OS X 64-bit, you can write your log statements like this:

NSLog(@"%ld",  myInt); 

while on iOS you can write:

NSLog(@"%d",  myInt); 

and it will all work without casts.

One reason to use casts anyway, at least in the non-UI code, 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);

This will also help your iOS code in a transition to 64 bit, should it ever come to iOS. Or when iOS and OS X get merged together down the line.

And notice this goes not just for NSLog statements, which are just debugging aids after all, but also for [NSString stringWithFormat:] and friends, 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


It keeps warning while using NSLog(@"%ld", (long)myInt);, but stops warning after change declaration to long myInt = 1804809223; in iOS 10.


OS X uses several data types—NSInteger, NSUInteger,CGFloat, and CFIndex—to provide a consistent means of representing values in 32- and 64-bit environments. In a 32-bit environment, NSInteger and NSUInteger are defined as int and unsigned int, respectively. In 64-bit environments, NSInteger and NSUInteger are defined as long and unsigned long, respectively. To avoid the need to use different printf-style type specifiers depending on the platform, you can use the specifiers shown in this link for both 32 bit and 64 bit environment.


Need Your Help

Is PHP serialize function compatible UTF-8?

php serialization utf-8

I have a site I want to migrate from ISO to UTF-8.

Detect in simulink if the current and past 4 values are same or not

simulink

I am interested in designing a simulink block which detects if the past 4 and the current input values are same or not. How to do it using the delay blocks and relational operators since the relati...