NSIntegerのNSLog / printf指定子?


131

A NSIntegerは、32ビットプラットフォームでは32ビット、64ビットプラットフォームでは64ビットです。NSLog常にサイズに一致する指定子はありNSIntegerますか?

セットアップ

  • Xcode 3.2.5
  • llvm 1.6コンパイラ(これは重要です。gccはこれを行いません)
  • GCC_WARN_TYPECHECK_CALLS_TO_PRINTF オン

これは私にいくつかの悲しみを引き起こしています:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    @autoreleasepool {
        NSInteger i = 0;
        NSLog(@"%d", i);
    }
    return 0;
}

32ビットコードの場合、%d指定子が必要です。しかし、%d指定子を使用すると、64ビット用にコンパイルするときに警告が表示され、%ld代わりに使用するように提案されます。

%ld64ビットサイズと一致させるために使用する場合、32ビットコード用にコンパイルすると、%d代わりに使用することを示唆する警告が表示されます。

両方の警告を一度に修正するにはどうすればよいですか?どちらでも機能する指定子はありますか?

これも影響[NSString stringWithFormat:][[NSString alloc] initWithFormat:]ます。

回答:


296

更新された回答:

すべてのアーキテクチャーで、警告を出さずに、zおよびt修飾子を使用して処理できます。NSIntegerNSUInteger

署名付き、署名なし、16進数に使用%zdしたい。%tu%tx

この情報は、Greg Parkerの好意によるものです。


元の答え:

公式の推奨されるアプローチは、使用することです%ld、あなたの指定子として、そして、実際の引数をキャストしますlong


6
これは間違いなく進むべき道ですが、私は使うかもしれないと思いますstatic inline NSIntToLong(NSInteger i) {return (long)i;}。これにより、タイプチェックが完全に無効になるのを回避できます(つまり、iのタイプが変更された場合)。
Steven Fisher

3
@ steven-fisherによる良い考え。避け警告付き:static inline long NSIntToLong(NSInteger i) {return (long)i;}
エリック

3
NSNumberを作成してログに記録することもできます。NSLog(@"%@",@(mynsint)); stackoverflow.com/questions/20355439/...
orkoden

2
@KevinBallardこれは重大なパフォーマンスの問題ではないはずです。とにかく、量産コードでは大量のNSLogを使用しないでください。何らかの理由で大量のものをログに記録する必要がある場合は、別のスレッドで実行してください。
orkoden 2014

4
Xcode 9.3以降、フォーマット引数としてNSIntegerを使用すると警告が出ます%zdValues of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead
Rob MacEachern

2

受け入れられた答えは絶対に合理的であり、標準に準拠しており、正しいです。唯一の問題は、それがもはや機能しないことです。これは完全にAppleの責任です。

フォーマット%zdは、size_tおよびssize_tのC / C ++標準フォーマットです。NSIntegerやNSUIntegerと同様に、size_tとssize_tは、32ビットシステムでは32ビット、64ビットシステムでは64ビットです。そして、それが%zdを使用してNSIntegerとNSUIntegerを印刷することができた理由です。

ただし、NSIntegerとNSUIntegerは、64ビットシステムでは「long」、32ビットシステムでは「int」と定義されます(64対32ビット)。今日、size_tはすべてのシステムで "long"に定義されています。これ、NSInteger(64または32ビット)と同じサイズですが、タイプが異なります。Appleの警告が変更されたため(ビット数が正しい場合でも、間違ったタイプをprintfに渡すことができません)、またはsize_tとssize_tの基本タイプが変更されました。どちらかわかりませんが、%zdはしばらく前に動作しなくなりました。現在、32ビットシステムと64ビットシステムの両方で警告なしにNSIntegerを印刷するフォーマットはありません

したがって、残念ながらできる唯一のことは、%ldを使用して、NSIntegerからlongに、またはNSUIntegerからunsigned longに値をキャストすることです。

32ビット用にビルドしなくなったら、キャストせずに%ldを使用できます。


0

フォーマッタは、標準のUNIX / POSIX printf関数から取得されます。使用%のLUのための符号なしの長い、長いため%ldの、長い長いため%のLLD、および%のLLUのための符号なしlong長いです。コンソールでman printfを試しますが、Macでは不完全です。Linuxのマンページはより明確ですhttp://www.manpages.info/linux/sprintf.3.html

どちらの警告もNSLog(@ "%lu"、(unsigned long)arg);でのみ修正できます。コードはiOS用に32および64ビットでコンパイルされるため、キャストと組み合わせる。それ以外の場合、コンパイルごとに個別の警告が作成されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.