Неявна неявна конверсія Objective-C втрачає цілісну точність 'NSUInteger' (він же 'непідписаний довгий') до попередження 'int'


187

Я працюю над деякими вправами і отримую попередження, яке говорить:

Неявне перетворення втрачає цілісну точність: 'NSUInteger' (він же 'довгий без підпису') до '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, тому попередження компілятора.

Дивіться також 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 vs armv7?
Шон Будрам

1
@ShaunBudhram Погляди на це немає. Я не бачив різниці. Це змінить лише додатки, які активно користуються процесором - ігри, наприклад, побачать перевагу, компільовану на 64 біт.
Роберт Дж. Клегг

7
"З 1 лютого 2015 року нові додатки для iOS, завантажені в App Store, повинні містити 64-бітну підтримку ..." - Новини та оновлення для розробників Apple, 20 жовтня 2014 р.
Pang

2
@JayprakashDubey: Apple не бачить попереджень вашого компілятора, оскільки ви подаєте двійково-скомпільовану програму в App Store. Тому ваш додаток не може бути відхилено через попередження компілятора. Звичайно, слід виправити їх, щоб ваша програма працювала правильно.
Martin R

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-розрядних, тому проблема не залишиться непоміченою.
Martin R

@Adrian: Якщо ви не заперечуєте, що ви пропонуєте запитувача?
moonman239

@ moonman239 Загалом, я б використовував змінну правильного типу, якщо це можливо (перша пропозиція MartinR) на відміну від кастингу (його другий). Як він зазначає, кастинг у цьому конкретному випадку безпечний, але я думаю, що це погана звичка потрапляти, оскільки це може мати несподівані наслідки (як у моєму прикладі). Я розмістив повідомлення, тому що мене вкусила ця конкретна ситуація (хоча це хороший момент щодо попередження компілятора ==, яке я, мабуть, пропустив).
Адріан

2
Я думаю, що підрахунок буде використовуватися набагато частіше, ніж indexOfObject, і роздуття for-loop з NSInteger просто не має "поганого" стилю кодування - це нісенітниця. Ви повинні стежити виключно за indexOfObject і переконайтеся, що ви використовуєте там NSIntegers, все, що просто рахує щось, є нормальним як int, особливо в фокусі методів
NikkyD

5

Клавіша зміни в проекті> Налаштування збірки " виберіть перевірку викликів для printf / scanf : НІ "

Пояснення: [Як це працює]

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

Сподіваюся, це спрацює

Інше попередження

ціль c неявна конверсія втрачає цілісну точність 'NSUInteger' (він же 'непідписаний довгий') до 'int

Змінити ключ " неявна конверсія на тип 32Bits> Налагодження> * 64 архітектура: Ні "

[ застереження: Це може скасувати інше попередження про конвертацію архітектури 64 біт] .


якщо ви хотіли просто перетворити свою 32-бітну бібліотеку в 64 біт, це перспективний варіант.
San

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.