Неявное преобразование 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;
}

Скриншот

Monkeyboy
источник

Ответы:

470

countМетод NSArrayвозвращает NSUInteger, и на 64-битной платформе OS X

  • NSUIntegerопределяется как unsigned longи
  • unsigned long 64-разрядное целое число без знака
  • int 32-разрядное целое число

Так intчто это «меньший» тип данных, чем NSUInteger, следовательно, предупреждение компилятора.

См. Также 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 исправило их все.
Роберт Дж. Клегг
1
@ Tander есть разница в производительности между компиляцией 64bit против armv7?
Шон Будхрам
1
@ShaunBudhram Судя по всему, нет. Я не видел никакой разницы. Это будет иметь значение только в приложениях, которые интенсивно используют ЦП - например, в играх будет полезно компилировать для 64-битной версии.
Роберт Дж. Клегг
7
«Начиная с 1 февраля 2015 г. новые приложения iOS, загружаемые в App Store, должны включать поддержку 64-разрядных систем ...» - Новости и обновления Apple Developer, 20 октября 2014 г.
Pang
2
@JayprakashDubey: Apple не видит предупреждений вашего компилятора, поскольку вы отправляете двоичное скомпилированное приложение в App Store. Поэтому ваше приложение не может быть отклонено из-за предупреждений компилятора. Конечно, вы должны исправить их, чтобы ваше приложение работало правильно.
Мартин Р
24

Вопреки ответу Мартина, приведение к int (или игнорирование предупреждения) не всегда безопасно, даже если вы знаете, что в вашем массиве не более 2 ^ 31-1 элементов. Не при компиляции для 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-битной системы, поэтому проблема не останется незамеченной.
Мартин Р
@Adrian: Если ты не возражаешь, что ты предлагаешь делать аскеру?
moonman239
@ moonman239 В общем, я бы использовал переменную правильного типа, если это возможно (первое предложение @ MartinR), в отличие от приведения (его второе). Как он указывает, в данном конкретном случае кастинг безопасен, но я думаю, что это плохая привычка, так как это может иметь неожиданные последствия (как в моем примере). Я написал, потому что я был укушен этой конкретной ситуацией (хотя это хороший момент относительно предупреждения компилятора ==, которое я, должно быть, пропустил).
Адриан
2
Я думаю, что count будет использоваться гораздо чаще, чем indexOfObject, и вздутие цикла for с NSInteger, просто чтобы не иметь «плохого» стиля кодирования, - нонсенс. Вы должны следить исключительно за indexOfObject и убедиться, что вы используете там NSIntegers, все, что просто что-то считает, прекрасно, как int, особенно в фокусе методов
NikkyD
5

Изменить ключ в Project> Build Setting " typecheck вызывает printf / scanf : НЕТ "

Пояснение: [Как это работает]

Проверьте вызовы printf, scanf и т. Д., Чтобы убедиться, что предоставленные аргументы имеют типы, соответствующие указанной строке формата, и что преобразования, указанные в строке формата, имеют смысл.

Надеюсь это сработает

Другое предупреждение

неявное преобразование target c теряет целочисленную точность «NSUInteger» (иначе «unsigned long») в «int»

Изменить ключ « неявное преобразование в 32-битный тип> Отладка> * 64 архитектура: нет »

[ предостережение: это может аннулировать другое предупреждение о преобразовании 64-битной архитектуры] .

Даршит Шах
источник
если вы хотите просто преобразовать 32-битную библиотеку в 64-битную, это многообещающий вариант.
Сан
2

Выполнение точного преобразования в int решает проблему в моем случае. Я была такая же проблема. Так:

int count = (int)[myColors count];
Владимир Деспотович
источник
или это называется "неявное"? LOL :) В любом случае, это сработало.
Владимир Деспотович