IOSの64ビットバージョンでは、_%d
_および_%u
_を使用してNSInteger
およびNSUInteger
をフォーマットすることはできなくなりました。 64ビットの場合、これらはlong
および_unsigned long
_ではなくint
および_unsigned int
_にtypedefされるためです。
したがって、NSIntegerを%dでフォーマットしようとすると、Xcodeは警告をスローします。 Xcodeは私たちにとって素晴らしいものであり、l接頭辞付きのフォーマット指定子とlongへの型キャストで構成される、これら2つのケースの代わりを提供します。次に、コードは基本的に次のようになります。
_NSLog(@"%ld", (long)i);
NSLog(@"%lu", (unsigned long)u);
_
あなたが私に尋ねれば、それは目の痛みです。
数日前、Twitterの誰かが、32ビットおよび64ビットのプラットフォームで、符号付き変数をフォーマットするためのフォーマット指定子_%zd
_および符号なし変数をフォーマットするための_%tu
_について言及しました。
_NSLog(@"%zd", i);
NSLog(@"%tu", u);
_
うまくいくようです。そして、私はタイプキャストよりも好きです。
しかし、正直なところ、なぜそれらが機能するのかわかりません。今のところ、どちらも基本的に私にとって魔法の値です。
少し調べてみたところ、z
プレフィックスは、次の形式指定子が_size_t
_と同じサイズであることを意味することがわかりました。しかし、プレフィックスt
の意味がまったくわかりません。だから私は2つの質問があります:
_%zd
_および_%tu
_は正確にはどういう意味ですか?
そして、Appleの提案の代わりに_%zd
_と_%tu
_を使用してlongに型キャストするのは安全ですか?
同様の質問とAppleの64ビット移行ガイドを知っています。これらはすべて%lu (unsigned long)
アプローチを推奨しています。型キャストの代替手段を求めています。
http://pubs.opengroup.org/onlinepubs/009695399/functions/printf.html から:
size_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;
ここで、__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_t
とNSInteger
はどちらもと同じタイプにtypedefされます。32ビットではint
、long
64ビット。したがって
NSLog(@"%td", i);
NSLog(@"%tu", u);
正常に動作し、現在のすべてのiOSおよびOS Xプラットフォームで警告なしにコンパイルします。
size_t
とNSUInteger
はすべてのプラットフォームで同じサイズですが、同じタイプではないため、
NSLog(@"%zu", u);
32ビット向けにコンパイルすると、実際には警告が表示されます。
しかし、この関係は(私の知る限り)どの標準でも修正されていないため、not安全であると考えます(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);
代わりにNSNumber
を使用することを好みます:
NSInteger myInteger = 3;
NSLog(@"%@", @(myInteger));
これはすべての状況で機能するわけではありませんが、NS(U)Integerフォーマットのほとんどを上記のものに置き換えました。
64ビットのような32ビットのビルド によると、別の解決策はNS_BUILD_32_LIKE_64
マクロを使用すると、%ld
および%lu
指定子とNSInteger
およびNSUInteger
を使用したキャストおよび警告なし。