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

Objective CXcodeCastingNsinteger

Objective C Problem Overview


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 corrected 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?

Objective C Solutions


Solution 1 - Objective C

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.

Solution 2 - Objective C

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.

Solution 3 - Objective C

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 https://stackoverflow.com/questions/20355439/nsinteger-and-nsuinteger-in-a-mixed-64bit-32bit-environment

Solution 4 - Objective C

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

Solution 5 - Objective C

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDaniel LeeView Question on Stackoverflow
Solution 1 - Objective CMartin RView Answer on Stackoverflow
Solution 2 - Objective CMonoloView Answer on Stackoverflow
Solution 3 - Objective CorkodenView Answer on Stackoverflow
Solution 4 - Objective CYao LiView Answer on Stackoverflow
Solution 5 - Objective CSaheb SinghView Answer on Stackoverflow