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

时间:2013-04-18 06:01:19

标签: objective-c xcode casting

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?

5 个答案:

答案 0 :(得分:192)

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

由于NSInteger是32位或64位,因此编译器建议,具体取决于平台 通常会将演员表添加到long

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

答案 1 :(得分:36)

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

因此,在OS X 64位上,您可以编写如下的日志语句:

NSLog(@"%ld",  myInt); 

在iOS上你可以写:

NSLog(@"%d",  myInt); 

并且没有演员阵容都可以。

无论如何,至少在非UI代码中使用强制转换的一个原因是好的代码往往是跨平台移植的,如果你明确地转换变量,它将在32位和64位上完全编译:

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

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

请注意,这不仅适用于NSLog语句,它毕竟只是调试辅助工具,也适用于[NSString stringWithFormat:]和朋友,它们是生产代码的合法元素。

答案 2 :(得分:22)

不要将NSInteger传递给NSLog,只需传递一个NSNumber即可。这将解决所有演员表并选择正确的字符串格式说明符。

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

它也适用于NSUIntegers而不必担心。 请参阅NSInteger and NSUInteger in a mixed 64bit / 32bit environment的答案

答案 3 :(得分:0)

在使用NSLog(@"%ld", (long)myInt);时会一直发出警告,但在iOS 10中更改声明到long myInt = 1804809223;后会停止警告。

答案 4 :(得分:-2)

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