54

%diOS の 64 ビット バージョンでは、 and%uをフォーマットするために使用できなくNSIntegerなりNSUIntegerました。long64 ビットの場合、これらはandunsigned longの代わりにintandにtypedef されるためですunsigned int

そのため、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_ttしかし、接頭辞の意味がまったくわかりません。だから私は2つの質問があります:

正確には何%zd%tu意味しますか?

Apple の提案の代わりに long にタイプキャストするの%zdは安全ですか?%tu


同様の質問とAppleの64ビット移行ガイドを認識しており、これらはすべて%lu (unsigned long)アプローチを推奨しています。型キャストに代わるものを求めています。

4

3 に答える 3

52

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

  • z
    後続の [...] 変換指定子が、size_tまたは対応する符号付き整数型引数に適用されることを指定します。
  • 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;

where__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 ビットと64 ビット。したがってintlong

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

現在のすべての iOS および OS X プラットフォームで正しく動作し、警告なしでコンパイルされます。

size_tNSUIntegerすべてのプラットフォームで同じサイズですが、同じタイプではないため、

NSLog(@"%zu", u);

32ビット用にコンパイルすると、実際には警告が表示されます。

しかし、この関係は(私が知る限り)どの標準でも固定されていないため、 安全とは見なしませんlong(ポインターと同じサイズを想定するのと同じ意味で、安全とは見なされません)。将来壊れるかもしれません。

私が知っている型キャストの唯一の代替手段は、プリプロセッサ マクロを使用して、「arm64 および 32 ビット アーキテクチャ用にコンパイルする場合の Foundation 型」への回答からのものです。

// 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);
于 2013-09-19T12:36:34.933 に答える
11

代わりにを使用することを好みNSNumberます:

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

これはすべての状況で機能するわけではありませんが、NS(U)Integer フォーマットのほとんどを上記のものに置き換えました。

于 2014-02-25T17:43:01.943 に答える