在32位和64位体系结构上格式化NS(U)Integer时types转换的替代方法?

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

所以如果你尝试用%d格式化NSInteger,Xcode会抛出警告。 Xcode对我们来说很好,并为这两种情况提供了一种替代scheme,它由l前缀格式说明符和longtypes组成。 那么我们的代码基本上是这样的:

 NSLog(@"%ld", (long)i); NSLog(@"%lu", (unsigned long)u); 

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

几天前,Twitter上有人提到了格式说明符%zd来格式化签名variables和%tu来格式化32和64位平台上的无符号variables。

 NSLog(@"%zd", i); NSLog(@"%tu", u); 

这似乎工作。 而我更喜欢types化。

但我真的不知道为什么这些工作。 现在这两个对我来说基本上都是神奇的价值。

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

%zd%tu究竟是什么意思?

是否可以安全地使用%zd%tu而不是Applebuild议将types转换为long?


我知道类似的问题和苹果64位转换指南,这些指南都推荐使用%lu (unsigned long)方法。 我要求一个替代types铸造。

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

  • ž
    指定以下转换说明符适用于size_t或相应的带符号整数types参数;
  • Ť
    指定以下转换说明符适用于ptrdiff_t或相应的无符号types参数;

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

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

在当前的OS X和iOS平台上

 typedef __SIZE_TYPE__ size_t; typedef __PTRDIFF_TYPE__ ptrdiff_t; 

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

 #define __SIZE_TYPE__ long unsigned int #define __PTRDIFF_TYPE__ int 

和编译器定义的64位

 #define __SIZE_TYPE__ long unsigned int #define __PTRDIFF_TYPE__ long int 

(这可能在Xcode版本之间有所变化,受@ user102008评论的启发,我已经用Xcode 6.2检查过了,并且更新了答案。)

所以ptrdiff_tNSInteger都是typedef'd 相同的typesint在32位和long在64位。 因此

 NSLog(@"%td", i); NSLog(@"%tu", u); 

在所有当前的iOS和OS X平台上正常工作并编译时不会出现警告。

size_tNSUInteger在所有平台上都有相同的大小,但是它们不是相同的types,所以

 NSLog(@"%zu", u); 

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

但是这个关系在任何标准上都是不固定的(据我所知),所以我认为这是安全的(就像假设long与指针的大小一样不被认为是安全的)。 它可能在未来破裂。

我所知道的唯一types转换的替代方法是使用预处理器macros从“ 编译为arm64和32位体系结构时的基础types ”的答案:

 // 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); 

我宁愿只是使用一个NSNumber

 NSInteger myInteger = 3; NSLog(@"%@", @(myInteger)); 

这在所有情况下都不起作用,但是我用上面的代替了大部分NS(U)Integer格式。

根据构build32位像64位 ,另一种解决scheme是定义NS_BUILD_32_LIKE_64macros,然后你可以简单地使用%ld%lu说明符与NSIntegerNSUInteger没有铸造和没有警告。