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

Dan*_*Lee 141 xcode casting objective-c

NSInteger myInt = 1804809223;
NSLog(@"%i", myInt); <==== 
Run Code Online (Sandbox Code Playgroud)

上面的代码产生错误:

Values of type "NSInteger" should not be used as format arguments: add an explicit cast to 'long' instead.
Run Code Online (Sandbox Code Playgroud)

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

Mar*_*n R 191

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

由于NSInteger是32位或64位,因此根据平台的不同,编译器建议long通常添加强制转换.

更新:由于iOS 7现在也支持64位,因此在编译iOS时可以获得相同的警告.

  • @BartSimpson:有一个明确的"long"大小写,如`NSLog(@"%ld",(long)myInt)`,它正确地工作在32位和64位上. (24认同)
  • @FullDecent:当然你可以在这里工作:`long myInt = [myNumber longValue];`.但是许多(Core)Foundation方法使用NS(U)Integer作为参数或返回值,因此一般问题仍然存在.此外,在您的应用程序中使用NS(U)Integer在64位设备上获得更大的可用范围是有意义的. (3认同)

Mon*_*olo 37

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

所以在OS X 64位上,您可以像这样编写日志语句:

NSLog(@"%ld",  myInt); 
Run Code Online (Sandbox Code Playgroud)

在iOS上你可以写:

NSLog(@"%d",  myInt); 
Run Code Online (Sandbox Code Playgroud)

它会在没有演员阵容的情况下奏效.

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

NSLog(@"%ld",  (long)myInt);
Run Code Online (Sandbox Code Playgroud)

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

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


ork*_*den 22

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

NSNumber foo = @9000;
NSLog(@"foo: %@", foo);
NSInteger bar = 9001;
NSLog(@"bar: %@", @(bar));
Run Code Online (Sandbox Code Playgroud)

它也适用于NSUIntegers而不必担心.请参阅混合64位/ 32位环境中的NSInteger和NSUInteger的答案

  • 我认为所选答案在技术上是问题的最佳答案,但如果你想知道如何避免每次出现并预防警告,那么我发现这是最好的解决方案. (2认同)