在32位和64位架构上格式化NS(U)Integer时输入类型的替代方法? [英] Alternatives to type casting when formatting NS(U)Integer on 32 and 64 bit architectures?

查看:211
本文介绍了在32位和64位架构上格式化NS(U)Integer时输入类型的替代方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于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 a size_t or the corresponding signed integer type argument;
  • t
    Specifies that a following [...] conversion specifier applies to a ptrdiff_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 the sizeof 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆