NSUInteger 不应该在格式字符串中使用?

46

这是我所有代码的荣耀:

[NSString stringWithFormat:@"Total Properties: %d", (int)[inArray count]];

这给我带来了一个 Xcode 5.1 的警告:

Values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead

好的,我有点困惑。这个值确实是一个32位整数,并且我将其转换为32位整数。那么它抱怨的NSUInteger是什么(我猜是计数),为什么这个转换不能解决它?


1
你确定这行代码会产生警告吗?我自己经常使用将它们转换为整数的方式,从未出现过错误。我在Xcode 5.1中进行了简单的示例检查。 - Michael Knudsen
为了避免未来读者的困惑:此警告出现与否取决于您正在编译的架构。 - Palpatim
4个回答

107

NSUInteger和NSInteger在32位(int)和64位(long)上的长度不同。为了使一个格式说明符适用于两种架构,您必须使用长格式说明符并将值转换为long类型:

Type    Format Specifier    Cast
----    ----------------    ----
NSInteger    %ld            long
NSUInteger   %lu            unsigned long

因此,例如,你的代码变成:

[NSString stringWithFormat:@"Total Properties: %lu", (unsigned long)[inArray count]];

其实要做的工作非常少,因为Xcode的Fix-It功能会自动为你完成这个任务。


谢谢Matt!它几乎像冠军一样工作,但“几乎”是因为修复似乎没有修复它。 - Maury Markowitz
你原来的整数转换可能会让它混淆。我在我的书籍代码中进行了大量类似的修复(最后四到五个提交位于https://github.com/mattneub/Programming-iOS-Book-Examples),Fix-It 大多数情况下都能正确处理。但有些必须手动完成。 - matt
然而,在两种架构上,NSInteger/NSUInteger与long/unsigned long的长度相同。那么为什么需要强制转换呢? - user102008
@matt:我的前提是正确的。如果您认为它们是错误的,请指出哪个陈述是错误的,以及您认为哪里存在问题。 - user102008

47

还可以使用“z”和“t”修饰符进行与 CPU 无关的格式字符串,例如:

NSInteger x = -1;
NSUInteger y = 99;
NSString *foo = [NSString stringWithFormat:@"NSInteger: %zd, NSUInteger: %tu", x, y];

9

NSUInteger的底层类型根据平台而变化:在32位平台上,它是一个32位无符号整数,在64位平台上,它是一个64位无符号整数。

字符串编程指南平台依赖性部分,苹果建议您执行以下操作:

为避免需要根据平台使用不同的printf样式类型说明符,您可以使用表3中显示的说明符。请注意,在某些情况下,您可能需要将值转换为其他类型。

对于NSUInteger,请使用格式%lu%lx,并将值强制转换为unsigned long

因此,为了避免警告,您需要按以下方式更改代码:

[NSString stringWithFormat:@"Total Properties: %lu", (unsigned long)[inArray count]];

unsigned long 相同。那么为什么需要强制转换呢? - user102008
@user102008 因为 NSUInteger 是依赖于平台的。 - Sergey Kalinichenko
那么 unsigned long 是什么 - user102008
1
@user102008 但是 unsigned long 在所有系统上都匹配 %lu,而 NSUInteger 可能会根据系统匹配 %lu%llu - Sergey Kalinichenko
你说“在32位平台上它是一个32位无符号整数,在64位平台上它是一个64位无符号整数”。这与unsigned long相同。 - user102008
3
这是一个巧合。NSUIntegerunsigned long的大小由不同的实体控制(Cocoa库的制造商与Objective-C编译器的制造商)。%lu始终保证与unsigned long匹配;对于NSUInteger没有这样的保证,因为它归不同的人所有。如果Cocoa制造商明天决定从下一个版本开始在所有平台上将NSUinteger设置为32位,他们可以百分之百地做到。这将破坏代码格式化而没有转换。 - Sergey Kalinichenko

0

你也可以尝试使用NSNumber方法:

[NSString stringWithFormat:@"Total Properties: %@", [[NSNumber numberWithUnsignedInteger:[inArray count]] stringValue]];

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