NSInteger変数をフォーマット引数として使用すると、なぜlongにキャストする必要があるのですか?


143
NSInteger myInt = 1804809223;
NSLog(@"%i", myInt); <==== 

上記のコードはエラーを生成します:

タイプ「NSInteger」の値は、フォーマット引数として使用しないでください。代わりに明示的なキャストを「long」に追加してください

訂正されたNSLogメッセージは実際にNSLog(@"%lg", (long) myInt);です。値を表示したいmyIntのに整数値をに変換する必要があるのはなぜlongですか?


1
@DanielLee、あなたが使用している場合NSLog(@"%ld", (long) myInt);longキャストはそれはと一致することですlの修飾子%ldが、として、そのすべてが不要であるNSLog(@"%d", myInt);、我々はそれを見ることができることを考えると(十分であるmyIntではありませんlong。ボトムライン、あなたはキャストmyInt形式で長い修飾子を使用している場合文字列ですが、長い文字列形式の修飾子を使用したり、longここにキャストしたりする必要はありません
Rob

1
どうやら、NSLog(@ "%i"、myInt);は正しくありません。上記で示したように、エラーメッセージが表示されるので十分です。
Daniel Lee

2
@DanielLee Martin Rのコメントを参照してください。iOSタグ付きで質問を投稿しましたが(長いわけNSIntegerはありません)、OS Xターゲット(はNSInteger あります long)でコンパイルしているようです。
Rob

ええ、わかりました。iOSとOSXがNSIntegerのビットとタイプを変えるとは知りませんでした。
Daniel Lee

回答:


193

OS X(64ビット)でコンパイルするとこの警告NSIntegerが表示されます。これは、そのプラットフォームではlong64ビット整数として定義されているためです。%i形式は、一方であり、int32ビットです。そのため、形式と実際のパラメーターのサイズが一致しません。

以来、NSInteger32ビットまたは64ビットであり、プラットフォームに応じて、コンパイラはにキャストを追加することをお勧めしますlong一般。

更新: iOS 7は64ビットもサポートするようになったため、iOS用にコンパイルするときに同じ警告が表示される可能性があります。


1
iOS 7でこのエラーが発生します。64ビットに設定すると、最新のiPhone 5Sだけが64ビットなので、古い32ビットデバイスで問題が発生しますか?
Pritesh Desai 2013

25
@BartSimpson:のように明示的に「ロング」にする場合NSLog(@"%ld", (long) myInt)、32ビットと64ビットで正しく動作します。
マーティンR

@MartinRキャストしている場合、そもそもlongを使用しないのはなぜですか?
William Entriken 2014年

3
@FullDecent:もちろん、ここで長く作業できますlong myInt = [myNumber longValue];。ただし、多くの(Core)FoundationメソッドはNS(U)Integerをパラメーターまたは戻り値として使用するため、一般的な問題が残ります。また、アプリではNS(U)Integerを使用して64ビットデバイスで利用可能な範囲を拡大することもできます。
マーティンR

39

フォーマット指定子がデータ型と一致する場合は、何にもキャストする必要はありません。NSIntegerがネイティブ型に関してどのように定義されるかについての詳細は、Martin Rの回答を参照してください。

したがって、64ビット環境用にビルドすることを目的としたコードの場合、次のようなログステートメントを記述できます。

NSLog(@"%ld",  myInt); 

32ビット環境では、次のように記述できます。

NSLog(@"%d",  myInt); 

そしてそれはすべてキャストなしで動作します。

とにかくキャストを使用する理由の1つは、優れたコードはプラットフォーム間で移植される傾向があるためです。変数を明示的にキャストすると、32ビットと64ビットの両方で問題なくコンパイルされます。

NSLog(@"%ld",  (long)myInt);

そしてこれは、結局のところデバッグの補助にすぎないNSLogステートメントだけでなく[NSString stringWithFormat:]、本番コードの正当な要素であるさまざまな派生メッセージにも当てはまることに注意してください。


1
さて、このハックが必要になったので、そもそもNSIntegerを最初から使用するのがベストプラクティスでしょうか。
William Entriken 2014年

@FullDecent書式文字列など、ランタイムで解釈されるのはコードの問題のみです。Alコンパイル済みコードはNSInteger typedefを利用しています。
Monolo 2014年

ある、それは、それが定義されているように定義されている理由の理由があるので、NSIntegerを使用することをお勧め。
gnasher729 2014年

22

NSIntegerをNSLogに渡す代わりに、NSNumberを渡すだけです。これにより、すべてのキャストが回避され、適切な文字列フォーマット指定子が選択されます。

NSNumber foo = @9000;
NSLog(@"foo: %@", foo);
NSInteger bar = 9001;
NSLog(@"bar: %@", @(bar));

それはNSUIntegersでも機能し、心配する必要はありません。64ビット/ 32ビットの混合環境でのNSIntegerおよびNSUIntegerへの回答を参照してください


2
選択された回答が技術的に質問に対する最良の回答であると思いますが、各発生をキャストすることを避けて警告を防ぐ方法を知りたい場合は、これが最良の解決策であると思います。
Daniel Wood

0

を使用している間は警告を出し続けますNSLog(@"%ld", (long)myInt);long myInt = 1804809223;、iOS 10でへの宣言を変更すると警告を停止します。


-2

OS Xは、NSInteger、NSUInteger、CGFloat、およびCFIndexのいくつかのデータ型を使用して、32ビット環境と64ビット環境で値を表す一貫した方法を提供します。32ビット環境では、NSIntegerおよびNSUIntegerは、それぞれintおよびunsigned intとして定義されます。64ビット環境では、NSIntegerおよびNSUIntegerはそれぞれlongおよびunsigned longとして定義されます。プラットフォームに応じて異なるprintfスタイルの型指定子を使用する必要を回避するために、このリンクに示されている指定子を32ビット環境と64ビット環境の両方に使用でき ます。

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