在32位和64位架构上格式化NS(U)Integer时输入类型的替代方法? [英] Alternatives to type casting when formatting NS(U)Integer on 32 and 64 bit architectures?
问题描述
对于64位版本的iOS,我们不能再使用%d
和%u
来格式化 NSInteger
和 NSUInteger
。因为对于64位,这些是typedef到 long
和 unsigned long
而不是 int
和 unsigned int
。
With the 64 bit version of iOS we can't use %d
and %u
anymore to format NSInteger
and NSUInteger
. Because for 64 bit those are typedef'd to long
and unsigned long
instead of int
and unsigned int
.
如果你尝试格式化NSInteger,Xcode会抛出警告%d。 Xcode对我们很好,并提供了这两种情况的替代品,它包括一个带有l前缀的格式说明符和一个长的类型转换。然后我们的代码基本上如下所示:
So Xcode will throw warnings if you try to format NSInteger with %d. Xcode is nice to us and offers an replacement for those two cases, which consists of a l-prefixed format specifier and a typecast to long. Then our code basically looks like this:
NSLog(@"%ld", (long)i);
NSLog(@"%lu", (unsigned long)u);
如果你问我,这是一个痛苦的眼睛。
Which, if you ask me, is a pain in the eye.
几天前Twitter上有人提到了格式说明符%zd
来格式化已签名的变量和%tu
在32位和64位平台上格式化无符号变量。
A couple of days ago someone at Twitter mentioned the format specifiers %zd
to format signed variables and %tu
to format unsigned variables on 32 and 64 bit plattforms.
NSLog(@"%zd", i);
NSLog(@"%tu", u);
这似乎有效。而且我更喜欢类型转换。
Which seems to work. And which I like more than typecasting.
但老实说,我不知道为什么这些工作。现在两者基本上都是我的神奇价值。
But I honestly have no idea why those work. Right now both are basically magic values for me.
我做了一些研究,发现 z
前缀意味着以下格式说明符具有相同的大小为 size_t
。但我完全不知道前缀 t
的意思。所以我有两个问题:
I did a bit of research and figured out that the z
prefix means that the following format specifier has the same size as size_t
. But I have absolutely no idea what the prefix t
means. So I have two questions:
究竟做什么%zd
和%tu
是什么意思?
What exactly do %zd
and %tu
mean?
使用%zd
和是否安全%tu
而不是苹果建议将类型转换为长?
And is it safe to use %zd
and %tu
instead of Apples suggestion to typecast to long?
我知道类似的问题和苹果64位转换指南,它们都推荐%lu(unsigned long)
方法。我要求替代类型转换。
I am aware of similar questions and Apples 64-Bit Transition guides, which all recommend the %lu (unsigned long)
approach. I am asking for an alternative to type casting.
推荐答案
来自 http://pubs.opengroup.org/onlinepubs/009695399/functions/printf.html :
- z
指定以下[...]转换说明符适用于size_t
或相应的有符号整数类型参数; - t
指定以下[...]转换说明符适用于ptrdiff_t
或相应的无符号类型参数;
- z
Specifies that a following [...] conversion specifier applies to asize_t
or the corresponding signed integer type argument; - t
Specifies that a following [...] conversion specifier applies to aptrdiff_t
or the corresponding unsigned type argument;
来自 http://en.wikipedia.org/wiki/Size_t#Size_and_pointer_difference_types :
-
size_t
用于表示特定实现中任何对象(包括数组)的大小。它用作sizeof
运算符的返回类型。 -
ptrdiff_t
用于表示指针之间的差异。
size_t
is used to represent the size of any object (including arrays) in the particular implementation. It is used as the return type of thesizeof
operator.ptrdiff_t
is used to represent the difference between pointers.
在当前的OS X和iOS平台上,我们有
On the current OS X and iOS platforms we have
typedef __SIZE_TYPE__ size_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
其中 __ SIZE_TYPE __
和 __ PTRDIFF_TYPE __
由
编译器预定义。对于32位,编译器定义
where __SIZE_TYPE__
and __PTRDIFF_TYPE__
are predefined by the
compiler. For 32-bit the compiler defines
#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进行了检查并更新了答案。)
(This may have changed between Xcode versions. Motivated by @user102008's comment, I have checked this with Xcode 6.2 and updated the answer.)
所以 ptrdiff_t
和 NSInteger
都是相同类型的类型定义:
int
在32位上, long
在64位上。因此
So ptrdiff_t
and NSInteger
are both typedef'd to the same type:
int
on 32-bit and long
on 64-bit. Therefore
NSLog(@"%td", i);
NSLog(@"%tu", u);
在所有当前的
iOS和OS X平台上正常工作并编译而不发出警告。
work correctly and compile without warnings on all current iOS and OS X platforms.
size_t
和 NSUInteger
在所有平台上具有相同的大小,但
它们的类型不同,所以
size_t
and NSUInteger
have the same size on all platforms, but
they are not the same type, so
NSLog(@"%zu", u);
在编译32位时实际发出警告。
actually gives a warning when compiling for 32-bit.
但这个关系并没有固定在任何标准中(据我所知),因此我会
不 认为它是安全的(在假设 long
具有相同的大小
,因为指针不被认为是安全的。它可能会在将来中断。
But this relation is not fixed in any standard (as far as I know), therefore I would
not consider it safe (in the same sense as assuming that long
has the same size
as a pointer is not considered safe). It might break in the future.
我知道的唯一替代类型转换的方法是编译arm64和32-bit架构时的基础类型,使用预处理器宏:
The only alternative to type casting that I know of is from the answer to "Foundation types when compiling for arm64 and 32-bit architecture", using preprocessor macros:
// 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);
这篇关于在32位和64位架构上格式化NS(U)Integer时输入类型的替代方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!