为什么将NSInteger变量用作格式参数时必须强制转换为long?


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

上面的代码产生一个错误:

“ NSInteger”类型的值不应用作格式参数。添加明确的强制转换为“长”

更正后的NSLog消息实际上是NSLog(@"%lg", (long) myInt);。为什么我要的整数值转换myIntlong如果我想的值显示?


1
@DanielLee,如果使用NSLog(@"%ld", (long) myInt);,则强制转换long是使其与的l限定符匹配%ld,但是所有这些都是不必要的,因为NSLog(@"%d", myInt);足够了(假设我们可以看到myInt不是long。)底线,myInt如果使用格式为long的限定符,则进行强制转换字符串,但无需使用长字符串格式限定符或long在此处
Rob

1
显然,NSLog(@“%i”,myInt);不是真的。足够了,因为您会收到如上所示的错误消息。
Daniel Lee

2
@DanielLee请参阅Martin R的评论。你发布你的问题与iOS标签(这里NSInteger长),但它听起来像你的OS X的目标(其中编译NSInteger long)。
罗布

嗯,我明白了。我不知道iOS和OSX是否会使NSInteger在位和类型上有所不同。
Daniel Lee

Answers:


193

如果在OS X(64位)上进行编译,则会收到此警告,因为在该平台NSInteger上定义为long并且是64位整数。的%i格式,而另一方面,为int,这是32位的。因此,格式和实际参数的大小不匹配。

由于NSInteger是32位或64位,因此取决于平台,编译器建议long通常添加强制类型转换。

更新:由于iOS 7现在也支持64位,因此在为iOS编译时会收到相同的警告。


1
我在iOS 7上收到此错误。由于如果我将最新的iPhone 5S设置为64位,那么只要它设置为64位,就会在较旧的32位设备上引起任何问题吗?
Pritesh Desai

25
@BartSimpson:使用一个明显的大小写为“ long”,如中所示NSLog(@"%ld", (long) myInt),它可以在32位和64位上正常工作。
Martin R

@MartinR如果我们要转换,为什么不首先使用long?
William Entriken 2014年

3
@FullDecent:当然,您可以在这里工作很长时间:long myInt = [myNumber longValue];。但是许多(Core)Foundation方法使用NS(U)Integer作为参数或返回值,因此仍然存在一般问题。同样,在您的应用中使用NS(U)Integer在64位设备上获得更大的可用范围也很有意义。
Martin R

39

如果格式说明符与数据类型匹配,则无需强制转换为任何内容。有关如何NSInteger根据本机类型定义的详细信息,请参见Martin R的答案。

因此,对于打算为64位环境构建的代码,可以这样编写日志语句:

NSLog(@"%ld",  myInt); 

而对于32位环境,您可以编写:

NSLog(@"%d",  myInt); 

而且无需铸造就可以正常工作。

无论如何,使用强制类型转换的一个原因是,良好的代码倾向于跨平台移植,并且如果您明确地强制转换变量,它将在32位和64位上清晰地编译:

NSLog(@"%ld",  (long)myInt);

并且请注意,不仅对于NSLog语句(这毕竟是调试辅助),而且对于[NSString stringWithFormat:]各种派生消息(它们都是生产代码的合法元素),这都是正确的。


1
因此,既然现在需要这种技巧,那么首先使用NSInteger还是最佳实践吗?
William Entriken 2014年

@FullDecent这只是解释为运行时的代码中的一个问题,例如格式字符串。所有已编译的代码都利用了NSInteger typedef。
Monolo 2014年

用NSInteger的最佳做法,因为不同的原因,它被定义它的定义方式很好的理由。
gnasher729 2014年

22

无需传递NSInteger到NSLog,只需传递NSNumber。这将解决所有强制类型转换,并选择正确的字符串格式说明符。

NSNumber foo = @9000;
NSLog(@"foo: %@", foo);
NSInteger bar = 9001;
NSLog(@"bar: %@", @(bar));

它也适用于NSUIntegers,而不必担心。在64位/ 32位混合环境中查看NSInteger和NSUInteger的答案


2
我认为所选的答案从技术上讲是对该问题的最佳答案,但是如果您想知道如何避免每次发生都发生问题并防止出现警告,那么我认为这是最佳的解决方案。
Daniel Wood

0

在使用时会保持警告NSLog(@"%ld", (long)myInt);,但long myInt = 1804809223;在iOS 10中将更改声明更改为后会停止警告。


-2

OS X使用几种数据类型-NSInteger,NSUInteger,CGFloat和CFIndex-提供一致的方式来表示32位和64位环境中的值。在32位环境中,NSInteger和NSUInteger分别定义为int和unsigned int。在64位环境中,NSInteger和NSUInteger分别定义为long和unsigned long。为了避免根据平台使用不同的printf样式类型说明符,可以在32位和64位环境中使用此链接中显示的说明符 。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.