NSLog/printf specifier for NSInteger?
A NSInteger
is 32 bits on 32-bit platforms, and 64 bits on 64-bit platforms. Is there a NSLog
specifier that always matches the size of NSInteger
?
Setup
- Xcode 3.2.5
- llvm 1.6 compiler (this is important; gcc doesn't do this)
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF
turned on
That's cau开发者_StackOverflow中文版sing me some grief here:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
@autoreleasepool {
NSInteger i = 0;
NSLog(@"%d", i);
}
return 0;
}
For 32 bit code, I need the %d
specifier. But if I use the %d
specifier, I get a warning when compiling for 64 bit suggesting I use %ld
instead.
If I use %ld
to match the 64 bit size, when compiling for 32 bit code I get a warning suggesting I use %d
instead.
How do I fix both warnings at once? Is there a specifier I can use that works on either?
This also impacts [NSString stringWithFormat:]
and [[NSString alloc] initWithFormat:]
.
Updated answer:
You can make use of the z
and t
modifiers to handle NSInteger
and NSUInteger
without warnings, on all architectures.
You want to use %zd
for signed, %tu
for unsigned, and %tx
for hex.
This information comes courtesy of Greg Parker.
Original answer:
The official recommended approach is to use %ld
as your specifier, and to cast the actual argument to a long
.
The accepted answer is absolutely reasonable, it is standard conforming, and correct. The only problem is that it doesn't work anymore, which is completely Apple's fault.
The format %zd is the C/C++ standard format for size_t and ssize_t. Like NSInteger and NSUInteger, size_t and ssize_t are 32 bit on a 32 bit system, and 64 bit on a 64 bit system. And that's why printing NSInteger and NSUInteger using %zd worked.
However, NSInteger and NSUInteger are defined as "long" on a 64 bit system, and as "int" on a 32 bit system (which is 64 vs 32 bit). Today, size_t is defined on "long" on all systems, which is the same size as NSInteger (either 64 or 32 bit), but a different type. Either Apple's warnings have changed (so it doesn't allow passing the wrong type to printf, even though it has the right number of bits), or the underlying types for size_t and ssize_t have changed. I don't know which one, but %zd stopped working some time ago. There is no format today that will print NSInteger without warning on both 32 and 64 bit systems.
So the only thing you can do unfortunately: Use %ld, and cast your values from NSInteger to long, or from NSUInteger to unsigned long.
Once you don't build for 32 bit anymore, you can just use %ld, without any cast.
The formatters come from the standard UNIX/POSIX printf function. Use %lu for unsigned long, %ld for long, %lld for long long, and %llu for unsigned long long. Try man printf on the console, but on Mac it is incomplete. The linux manpages are more explicit http://www.manpages.info/linux/sprintf.3.html
Both warnings can only be fixed by NSLog(@"%lu", (unsigned long)arg); combined with a cast as the code will be compiled in 32 AND 64 bit for iOS. Otherwise each compilation creates a separate warning.
精彩评论