为什么NSIntegervariables在作为格式参数使用时必须转换为long?

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

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

 Values of type "NSInteger" should not be used as format arguments: add an explicit cast to 'long' instead. 

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

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

由于NSInteger是32位或64位的,因此根据平台的不同,编译器build议一般添加一个强制转换。

更新:由于iOS 7现在也支持64位,所以在为iOS编译时可以得到相同的警告。

如果格式说明符符合您的数据types,则不必转换为任何内容。 请参阅Martin R的答案,将NSInteger定义为本机types。

所以在OS X 64位上,你可以写下你的日志语句:

 NSLog(@"%ld", myInt); 

而在iOS上,你可以写:

 NSLog(@"%d", myInt); 

这一切都将工作,没有施放。

无论如何,至less在非UI代码中使用强制转换的一个原因是好的代码倾向于跨平台移植,如果你显式地转换你的variables,它将在32位和64位上干净地编译:

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

这也将帮助你的iOS代码过渡到64位,如果它来到iOS。 或者当iOS和OS X合并在一起。

并注意到这不仅仅是NSLog语句,毕竟它只是debugging帮助,而且也是[NSString stringWithFormat:]和朋友,它们是生产代码的合法元素。

而不是传递NSInteger到NSLog,只是传递一个NSNumber。 这将绕过所有的演员,并select正确的string格式说明符。

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

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

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

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