【问题标题】:NSLog/printf specifier for NSInteger?NSInteger 的 NSLog/printf 说明符?
【发布时间】:2011-05-23 05:52:18
【问题描述】:

NSInteger 在 32 位平台上为 32 位,在 64 位平台上为 64 位。是否存在始终与 NSInteger 的大小匹配的 NSLog 说明符?

设置

  • Xcode 3.2.5
  • llvm 1.6 编译器(这很重要;gcc 不这样做)
  • GCC_WARN_TYPECHECK_CALLS_TO_PRINTF 已开启

这让我有些悲伤:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    @autoreleasepool {
        NSInteger i = 0;
        NSLog(@"%d", i);
    }
    return 0;
}

对于 32 位代码,我需要 %d 说明符。但是如果我使用 %d 说明符,我会在编译 64 位时收到警告,建议我改用 %ld

如果我使用 %ld 来匹配 64 位大小,则在编译 32 位代码时,我会收到一条警告,建议我改用 %d

如何同时修复两个警告?有没有我可以使用的说明符?

这也会影响[NSString stringWithFormat:][[NSString alloc] initWithFormat:]

【问题讨论】:

    标签: objective-c cocoa 32bit-64bit nslog nsinteger


    【解决方案1】:

    更新答案:

    您可以在所有架构上使用zt 修饰符来处理NSIntegerNSUInteger 而不会出现警告。

    您想将%zd 用于签名,%tu 用于未签名,%tx 用于十六进制。

    此信息来自Greg Parker


    原答案:

    official recommended approach 是使用%ld 作为说明符,并将实际参数转换为long

    【讨论】:

    • 这绝对是要走的路,但我想我可能会使用static inline NSIntToLong(NSInteger i) {return (long)i;}。这避免了完全禁用类型检查(即如果 i 的类型发生变化)。
    • @steven-fisher 的好想法。避免警告:static inline long NSIntToLong(NSInteger i) {return (long)i;}
    • 你也可以创建一个 NSNumber 并记录下来。 NSLog(@"%@",@(mynsint));stackoverflow.com/questions/20355439/…
    • @KevinBallard 这应该不是一个严重的性能问题。无论如何,您都不应该在生产代码中使用大量 NSLog。如果您出于某种原因必须记录大量内容,请在单独的线程上进行。
    • 从 Xcode 9.3 开始,当使用 NSInteger 作为%zd 的格式参数时会出现警告:Values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead
    【解决方案2】:

    接受的答案绝对合理,符合标准且正确。唯一的问题是它不再工作了,这完全是苹果的错。

    %zd 格式是 size_t 和 ssize_t 的 C/C++ 标准格式。与 NSInteger 和 NSUInteger 一样,size_t 和 ssize_t 在 32 位系统上是 32 位,在 64 位系统上是 64 位。这就是使用 %zd 打印 NSInteger 和 NSUInteger 的原因。

    但是,NSInteger 和 NSUInteger 在 64 位系统上定义为“long”,在 32 位系统上定义为“int”(64 位与 32 位)。今天,size_t 在所有系统上都定义为“long”, 与 NSInteger(64 位或 32 位)大小相同,但类型不同。 Apple 的警告已更改(因此它不允许将错误的类型传递给 printf,即使它具有正确的位数),或者 size_t 和 ssize_t 的基础类型已更改。我不知道是哪一个,但 %zd 前段时间停止了工作。今天有 no 格式可以在 32 位和 64 位系统上打印 NSInteger 而不会发出警告。

    不幸的是,您唯一能做的就是:使用 %ld,并将您的值从 NSInteger 转换为 long,或从 NSUInteger 转换为 unsigned long。

    一旦您不再为 32 位构建,您可以直接使用 %ld,无需任何转换。

    【讨论】:

      【解决方案3】:

      格式化程序来自标准的 UNIX/POSIX printf 函数。 %lu 用于 unsigned long,%ld 用于 long,%lld 用于 long long,%llu 用于 unsigned long long。在控制台上尝试 man printf ,但在 Mac 上它是不完整的。 linux 手册页更明确http://www.manpages.info/linux/sprintf.3.html

      这两个警告只能通过 NSLog(@"%lu", (unsigned long)arg);结合演员表,因为代码将为 iOS 编译为 32 位和 64 位。否则每次编译都会创建一个单独的警告。

      【讨论】:

        猜你喜欢
        • 2014-01-07
        • 2017-11-16
        • 2012-03-14
        • 1970-01-01
        • 2012-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-17
        相关资源
        最近更新 更多