在混合的64位/32位环境中,NSInteger和NSUInteger的含义是什么?

28

我在NSLog / NSAssert等调用中使用了相当数量的字符串格式说明符,其中使用了 %d%u 分别与 NSInteger(= 32位上的int)NSUInteger(= 32位上的unsigned int) 类型配对。

将应用程序转换为64位时,会出现警告(当然),因为现在需要 %ld %lu 来表示longunsigned long类型。

简单地转换格式说明符当然会引入32位构建中的反向警告。所以,我唯一能想到的解决方案是使用64位格式说明符,并在32位构建中给出警告时,在所有地方都强制转换为64位值类型。

但我在想,也许有针对NSIntegerNSUInteger类型的格式说明符可以在不进行强制转换的情况下在两种架构上工作?


我们能否只是禁用警告? - KarenAnne
3个回答

61

我认为最安全的方法是将它们装箱成NSNumber实例。

NSLog(@"Number is %@", @(number)); // use the highest level of abstraction

由于标记指针的神奇作用,这个对象通常不需要创建新的。

如果你确实不想使用NSNumber,可以像其他人建议的那样手动转换基本类型:

NSLog(@"Number is %ld", (long)number); // works the same on 32-bit and 64-bit

1
为什么这比强制转换为长整型更“安全”? - Martin R
6
如果您将NSUInteger 强制转换为 unsigned long,但将其更改为 NSInteger,则在负值情况下会出现错误行为且没有任何警告。使用@()可以保证在所有情况下正常工作。 - ilya n.
1
如果你将 NSUInteger 强制转换为 long,那么在 number > ULONG_MAX 的情况下就会出现错误(尽管这是理论上的,但仍然不美观)。 - ilya n.
1
@NikolaiRuhe:是的,我现在看到了优点。我仍然不愿意为打印整数而创建一个对象,并且您会失去一些功能(例如指定宽度%10d或%x用于十六进制输出)。但是,对于调试来说,这是一个很好的替代方案。 - Martin R
1
@NikolaiRuhe,标记指针很便宜(不需要malloc)。关于“%10d”的观点很好。十六进制-如何使用“[NSData dataWithBytes:&number length:sizeof(number)]”? - ilya n.
显示剩余2条评论

38

在日志输出时,你也可以使用%zdNSInteger)和%tuNSUInteger)。

NSInteger integer = 1;
NSLog(@"first number: %zd", integer);

NSUInteger uinteger = 1;
NSLog(@"second number: %tu", uinteger);

同样可以在这里找到。


1
+1 这应该是最好的。来自维基百科 z:对于整数类型,导致 printf 期望一个 size_t 大小的整数参数。 - superarts.org

4
很抱歉,没有直接对应NS(U)Integer的printf格式。因此,为了实现与体系结构无关的代码,您需要将所有内容转换为“long”变量(正如Xcode的“修复”建议所示):
NSInteger i = ...;
NSLog(@"%ld", (long)i);

我所知道的唯一选择来自于 在编译arm64和32位架构时使用Foundation类型 相关问题的回答:
// In the precompiled header file:
#if __LP64__
#define NSI "ld"
#define NSU "lu"
#else
#define NSI "d"
#define NSU "u"
#endif

NSInteger i = ...;
NSLog(@"i=%"NSI, i);

使用预处理宏(但即使该答案的作者也称其为“明显可怕的方法”)。


好的。这就是标准类型所使用的<inttypes.h>头文件的作用。 - Todd Lehman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接