在32位和64位体系结构上格式化NS(U)Integer时输入类型的替代方法?

Mat*_*uch 53 printf objective-c nsinteger ios

随着iOS版的64位版本,我们不能使用%d%u再格式化NSIntegerNSUInteger.因为对于64位,这些是typedef'd longunsigned long不是intunsigned int.

因此,如果您尝试使用%d格式化NSInteger,Xcode将发出警告.Xcode对我们很好,并提供了这两种情况的替代品,它包括一个带有l前缀的格式说明符和一个长的类型转换.然后我们的代码基本上是这样的:

NSLog(@"%ld", (long)i);
NSLog(@"%lu", (unsigned long)u);
Run Code Online (Sandbox Code Playgroud)

如果你问我,这是一个痛苦的眼睛.

几天前,Twitter上有人提到格式说明符%zd来格式化签名变量和%tu在32位和64位平台上格式化无符号变量.

NSLog(@"%zd", i);
NSLog(@"%tu", u);
Run Code Online (Sandbox Code Playgroud)

这似乎有效.而且我更喜欢类型转换.

但老实说,我不知道为什么这些工作.现在两者对我来说基本上都是神奇的价值观.

我做了一些研究,并发现z前缀意味着以下格式说明符具有相同的大小size_t.但我完全不知道前缀是什么t意味着.所以我有两个问题:

究竟是什么%zd%tu意味着什么呢?

是否可以安全使用%zd,%tu而不是苹果建议长期使用?


我知道类似的问题和Apples 64位过渡指南,它们都推荐这种%lu (unsigned long)方法.我要求替代铸造.

Mar*_*n R 52

来自http://pubs.opengroup.org/onlinepubs/009695399/functions/printf.html:

  • z
    指定以下[...]转换说明符适用于size_t或对应的有符号整数类型参数;
  • t
    指定以下[...]转换说明符适用于ptrdiff_t或相应的无符号类型参数;

http://en.wikipedia.org/wiki/Size_t#Size_and_pointer_difference_types:

  • size_t用于表示特定实现中任何对象(包括数组)的大小.它用作sizeof运算符的返回类型.
  • ptrdiff_t 用于表示指针之间的差异.

在当前的OS X和iOS平台上我们有

typedef __SIZE_TYPE__ size_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
Run Code Online (Sandbox Code Playgroud)

其中__SIZE_TYPE____PTRDIFF_TYPE__由编译器中预定义.对于32位编译器定义

#define __SIZE_TYPE__ long unsigned int
#define __PTRDIFF_TYPE__ int
Run Code Online (Sandbox Code Playgroud)

对于64位编译器定义

#define __SIZE_TYPE__ long unsigned int
#define __PTRDIFF_TYPE__ long int
Run Code Online (Sandbox Code Playgroud)

(这可能在Xcode版本之间发生了变化.由@ user102008的评论激发,我已经用Xcode 6.2检查了这个并更新了答案.)

因此ptrdiff_t,NSInteger它们都是相同类型的 typedef : int在32位和long64位上.因此

NSLog(@"%td", i);
NSLog(@"%tu", u);
Run Code Online (Sandbox Code Playgroud)

在所有当前的iOS和OS X平台上正常工作并在没有警告的情况下进行编译.

size_t并且NSUInteger在所有平台上具有相同的大小,但它们的类型不同,所以

NSLog(@"%zu", u);
Run Code Online (Sandbox Code Playgroud)

实际上在编译32位时会发出警告.

但是这个关系在任何标准中都没有固定(据我所知),因此我 认为它是安全的(与假设long与指针大小相同并不被认为是安全的意义相同).它可能在未来破裂.

我所知道的唯一的类型转换替代方法是使用预处理器宏来回答" 编译arm64和32位架构时的基础类型 ":

// In your prefix header or something
#if __LP64__
#define NSI "ld"
#define NSU "lu"
#else
#define NSI "d"
#define NSU "u"
#endif

NSLog(@"i=%"NSI, i);
NSLog(@"u=%"NSU, u);
Run Code Online (Sandbox Code Playgroud)

  • 谢谢.当我第一次听到`zd`和`tu`时,基本上就是我想到的"意外相同大小"部分.我想我坚持使用类型转换,#define外观看起来更糟糕. (2认同)

Sco*_*ets 11

我更喜欢用一个NSNumber代替:

NSInteger myInteger = 3;
NSLog(@"%@", @(myInteger));
Run Code Online (Sandbox Code Playgroud)

这并不适用于所有情况,但我用上面的代码替换了我的大多数NS(U)整数格式.

  • 我喜欢这个,在某些情况下会毫不犹豫地使用它.请记住,创建和销毁临时对象及其描述会产生一些开销.哦,你丢失了字段宽度和精度说明符(例如对于CGFloat). (3认同)