【问题标题】:Why does an NSInteger variable have to be cast to long when used as a format argument?为什么 NSInteger 变量在用作格式参数时必须转换为 long?
【发布时间】:2013-04-18 06:01:19
【问题描述】:
NSInteger myInt = 1804809223;
NSLog(@"%i", myInt); <==== 

上面的代码产生错误:

“NSInteger”类型的值不应用作格式参数;改为将显式强制转换为“long”

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

【问题讨论】:

  • @DanielLee,如果你使用NSLog(@"%ld", (long) myInt);,long 演员表是为了使它与%ld 的l 限定符匹配,但所有这些都是不必要的,因为NSLog(@"%d", myInt);就足够了(假设我们可以看到myInt 不是long。底线,如果在格式字符串中使用长限定符,你可以转换myInt,但不需要使用长字符串格式限定符或long 在此处转换.
  • 显然,NSLog(@"%i", myInt);就足够了,因为您将收到我上面显示的错误消息。
  • @DanielLee 查看 Martin R 的评论。您使用 iOS 标签发布了您的问题(其中NSInteger 是 not 长),但听起来您正在使用 OS X 目标进行编译(其中NSInteger is @ 987654337@).
  • 啊,我明白了。我不知道 iOS 和 OSX 会使 NSInteger 在位和类型上有所不同。

标签: objective-c xcode casting nsinteger


【解决方案1】:

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

由于NSInteger是32位还是64位,根据平台不同,编译器推荐 通常为long 添加演员表。

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

【讨论】:

  • 我在 iOS 7 上收到此错误。因为只有最新的 iPhone 5S 是 64 位,如果我设置它,它会在旧的 32 位设备上造成任何问题吗?
  • @BartSimpson:使用明确的“long”大小写,如NSLog(@"%ld", (long) myInt),它可以在 32 位和 64 位上正常工作。
  • @MartinR 如果我们正在铸造,为什么不首先使用 long 呢?
  • @FullDecent:当然你可以在这里使用 long:long myInt = [myNumber longValue];。但是很多 (Core)Foundation 方法使用 NS(U)Integer 作为参数或返回值,所以一般问题仍然存在。此外,在您的应用中使用 NS(U)Integer 在 64 位设备上获得更大的可用范围也是有意义的。
【解决方案2】:

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

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

NSLog(@"%ld",  myInt); 

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

NSLog(@"%d",  myInt); 

而且它可以在没有演员表的情况下工作。

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

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

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

【讨论】:

  • 既然需要这个 hack,那么首先使用 NSInteger 仍然是最佳实践吗?
  • @FullDecent 只是解释运行时的代码有问题,比如格式字符串。所有编译的代码都利用了 NSInteger typedef。
  • 使用 NSInteger 是最佳实践,因为它的定义方式有充分的理由。
【解决方案3】:

不要将 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的回复

【讨论】:

  • 我认为选择的答案在技术上是该问题的最佳答案,但如果您想知道如何避免每次出现并防止警告,那么我发现这是最好的解决方案。
【解决方案4】:

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

【讨论】:

    【解决方案5】:

    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 位环境。

    【讨论】:

      猜你喜欢
      • 2021-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-31
      • 1970-01-01
      • 2020-06-04
      • 2020-05-16
      相关资源
      最近更新 更多