Objective-Cの暗黙的な変換は整数精度「NSUInteger」(別名「unsigned long」)を「int」警告に失います


187

私はいくつかの演習を進めており、次のような警告が表示されます:

暗黙的な変換で整数の精度が失われます: 'NSUInteger'(別名 'unsigned long')から 'int'

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    @autoreleasepool {

        NSArray *myColors;

        int i;
        int count;

        myColors = @[@"Red", @"Green", @"Blue", @"Yellow"];

        count = myColors.count; //  <<< issue warning here

        for (i = 0; i < count; i++)

        NSLog (@"Element %i = %@", i, [myColors objectAtIndex: i]);
    }

    return 0;
}

スクリーンショット

回答:


470

countメソッドはをNSArray返しNSUInteger、64ビットOS Xプラットフォームでは

  • NSUIntegerとして定義されunsigned long
  • unsigned long 64ビットの符号なし整数です。
  • int 32ビット整数です。

したがって、intは「より小さい」データ型なNSUIntegerので、コンパイラの警告が表示されます。

「Foundation Data Types Reference」のNSUIntegerも参照してください。

32ビットアプリケーションを構築する場合、NSUIntegerは32ビットの符号なし整数です。64ビットアプリケーションは、NSUIntegerを64ビットの符号なし整数として扱います。

コンパイラの警告を修正するには、ローカルcount変数を次のように宣言することができます

NSUInteger count;

または(配列に2^31-1要素以上の要素が含まれないことが確実である場合)、明示的なキャストを追加します。

int count = (int)[myColors count];

19
追加するだけです-私のXcode 5プロジェクトで突然警告とエラーのがらくたのロードを受け取ったので、私はこの回答に投票しました。ビルド設定を確認する64ビットについて説明しました。Xcodeはそれをエラーを投げた64ビットモードに変更しました。それをarvm7に戻すと、すべてが修正されました。
ロバートJ.クレッグ2014年

1
@Tander 64ビットのコンパイルとarmv7のコンパイルの間にパフォーマンスの違いはありますか?
Shaun Budhram 2014年

1
@ShaunBudhram見た目は違います。違いは見たことがありません。CPUを多用するアプリでのみ違いが生じます。たとえば、ゲームでは64ビット向けにコンパイルするとメリットがあります。
ロバートJ.クレッグ

7
「2015年2月1日以降、App Storeにアップロードされる新しいiOSアプリには64ビットのサポートが含まれている必要があります ...」- Apple Developer News and Updates、October
Pang

2
@JayprakashDubey:バイナリでコンパイルされたアプリケーションをApp Storeに送信したため、Appleはコンパイラの警告を表示しません。したがって、コンパイラの警告のためにアプリを拒否することはできません。もちろん、アプリを正しく動作させるために修正する必要があります。
マーティンR

24

Martinの回答とは逆に、配列に2 ^ 31-1を超える要素がないことがわかっていても、intへのキャスト(または警告を無視)は常に安全であるとは限りません。64ビット用にコンパイルしているときではありません。

例えば:

NSArray *array = @[@"a", @"b", @"c"];

int i = (int) [array indexOfObject:@"d"];
// indexOfObject returned NSNotFound, which is NSIntegerMax, which is LONG_MAX in 64 bit.
// We cast this to int and got -1.
// But -1 != NSNotFound. Trouble ahead!

if (i == NSNotFound) {
    // thought we'd get here, but we don't
    NSLog(@"it's not here");
}
else {
    // this is what actually happens
    NSLog(@"it's here: %d", i);

    // **** crash horribly ****
    NSLog(@"the object is %@", array[i]);
}

6
の結果をキャストするのindexOfObject:は悪い考えです。私の答えは質問の特定のコードを対象としており、countメソッドはを返すことができませんNSNotFound。一般に、intにキャストしたり警告を無視したりすることはお勧めしませんでした。それが不明確な場合は申し訳ありません。実際、サンプルコードはif (i == NSNotFound)、64ビット用にコンパイルされた場合に警告を生成するため、問題が気付かれることはありません。
マーティンR

@エイドリアン:よろしければ、質問者に何を勧めますか?
moonman239 2015年

@ moonman239一般に、キャスト(彼の2番目)ではなく、可能な場合は正しいタイプの変数(@MartinRの最初の提案)を使用します。彼が指摘しているように、この特定のケースではキャスティングは安全ですが、予期しない結果をもたらす可能性があるため(私の例のように)、それを始めるのは悪い習慣だと思います。私はこの特定の状況に悩まされているために投稿しました(ただし、==コンパイラの警告については良い点ですが、見逃していたに違いありません)。
エイドリアン

2
countはindexOfObjectよりもはるかに頻繁に使用され、「悪い」コーディングスタイルを持たないためにNSIntegerでforループを膨らませることはナンセンスです。indexOfObjectのみを監視し、そこでNSIntegersを使用していることを確認する必要があります。特に、メソッドフォーカス内では、何かを単純に数えるものはすべて問題ありません
NikkyD

5

[プロジェクト]> [ビルド設定]のキーを変更します " typecheckがprintf / scanfを呼び出しますいいえ "

説明: [仕組み]

printfやscanfなどの呼び出しを調べて、指定された引数が指定されたフォーマット文字列に適切なタイプであること、およびフォーマット文字列で指定された変換が意味があることを確認してください。

それがうまくいくことを願っています

その他の警告

目的cの暗黙の変換は整数精度 'NSUInteger'(別名 'unsigned long')を 'intに失います

キーを変更 " 32ビットタイプへの暗黙の変換>デバッグ> * 64アーキテクチャ:いいえ "

[ 注意: 64ビットアーキテクチャの変換に関する他の警告が無効になる場合があります]


32ビットライブラリを64ビットに変換したいだけなら、これは有望なオプションです。
サン

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