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

在iOS的64位版本中,我们无法再使用%lu (unsigned long)%tu格式化t130和NSUInteger131。因为对于64位,这些类型已定义为longunsigned long,而不是intunsigned int

因此,如果您尝试使用%d格式化NSInteger,则Xcode将引发警告。 Xcode对我们很好,可以替代这两种情况,其中包括一个l前缀格式说明符和一个long类型转换。 然后我们的代码基本上如下所示:

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

如果您问我,那是眼睛上的疼痛。

几天前,Twitter上有人提到格式说明符%lu (unsigned long)用于格式化有符号变量,而%tu用于格式化32和64位平台上的无符号变量。

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

这似乎可行。 而且我更喜欢打字。

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

我做了一些研究,发现2699844369636636656128前缀意味着以下格式说明符的大小与2699844369636656656129相同。但是我完全不知道t前缀的含义。 所以我有两个问题:

%lu (unsigned long)%tu分别是什么意思?

而且,使用%lu (unsigned long)%tu代替苹果建议长时间打字的方法是否安全?


我知道类似的问题以及Apples 64位过渡指南,它们都建议使用%lu (unsigned long)128方法。 我正在寻找一种替代类型转换的方法。

Matthias Bauch asked 2020-01-12T20:30:11Z
3个解决方案
52 votes

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

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

并来自[http://en.wikipedia.org/wiki/Size_t#Size_and_pointer_difference_types:]

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

在当前的OS X和iOS平台上,

typedef __SIZE_TYPE__ size_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;

其中longNSUInteger是由编译器。 对于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进行了检查并更新了答案。)

因此longNSUInteger都被定义为同一类型:在32位上为int,在64位上为long。 因此

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

可以正常工作,并且在所有当前版本上都不会发出警告iOS和OS X平台。

在所有平台上,longNSUInteger具有相同的大小,但是它们不是同一类型,所以

NSLog(@"%zu", u);

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

但是这种关系在任何标准中都不是固定的(据我所知),因此我会不认为安全(与假定2699845459987987923968具有相同的大小相同)作为指针不被认为是安全的)。 将来可能会中断。

我知道类型转换的唯一替代方法是使用预处理器宏从“针对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);
Martin R answered 2020-01-12T20:31:51Z
11 votes

我更喜欢只使用NSNumber

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

这并非在所有情况下都有效,但是我已经用上面的代码替换了大多数NS(U)Integer格式。

Scott Berrevoets answered 2020-01-12T20:32:16Z
2 votes

根据将32位构建为类似于64位的方法,另一种解决方案是定义NS_BUILD_32_LIKE_64宏,然后可以简单地将%ld%lu说明符与NSIntegerNSUInteger一起使用,而无需强制转换和警告。

user102008 answered 2020-01-12T20:32:36Z
translate from https://stackoverflow.com:/questions/18893880/alternatives-to-type-casting-when-formatting-nsuinteger-on-32-and-64-bit-archi