La conversione implicita Objective-C perde la precisione dell'intero 'NSUInteger' (aka 'unsigned long') nell'avvertimento 'int'


187

Sto lavorando ad alcuni esercizi e ho ricevuto un avviso che afferma:

La conversione implicita perde la precisione dei numeri interi: da "NSUInteger" (aka "unsigned long") a "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;
}

Immagine dello schermo

Risposte:


470

Il countmetodo di NSArrayrestituisce un NSUIntegere sulla piattaforma OS X a 64 bit

  • NSUIntegerè definito come unsigned longe
  • unsigned long è un numero intero senza segno a 64 bit.
  • int è un numero intero a 32 bit.

Quindi intè un tipo di dati "più piccolo" di NSUInteger, quindi l'avvertimento del compilatore.

Vedi anche NSUInteger nel "Riferimento tipi di dati di base":

Quando si creano applicazioni a 32 bit, NSUInteger è un numero intero senza segno a 32 bit. Un'applicazione a 64 bit considera NSUInteger come un numero intero senza segno a 64 bit.

Per correggere l'avviso del compilatore, è possibile dichiarare la countvariabile locale come

NSUInteger count;

oppure (se sei sicuro che il tuo array non conterrà mai più di 2^31-1elementi!), aggiungi un cast esplicito:

int count = (int)[myColors count];

19
Solo per aggiungere: ho votato a favore di questa risposta quando ho ricevuto un sacco di avvertimenti ed errori all'improvviso nel mio progetto Xcode 5. Hai menzionato 64 bit che mi ha portato a guardare le mie impostazioni di build. Xcode l'ha cambiato in modalità 64 bit che ha generato errori. La modifica in arvm7 ha risolto tutti.
Robert J. Clegg,

1
@Tander c'è una differenza di prestazioni tra compilare 64 bit vs armv7?
Shaun Budhram,

1
@ShaunBudhram A quanto pare no. Non ho visto alcuna differenza. Farà solo la differenza nelle app che usano pesantemente la CPU, ad esempio i giochi vedrebbero un vantaggio compilarsi per 64 bit.
Robert J. Clegg,

7
"A partire dal 1 ° febbraio 2015, le nuove app iOS caricate sull'App Store devono includere il supporto a 64 bit ..." - Notizie e aggiornamenti per gli sviluppatori Apple, 20 ottobre 2014
Pang

2
@JayprakashDubey: Apple non vede gli avvisi del compilatore perché invii l'applicazione compilata binaria all'App Store. Pertanto, l'app non può essere rifiutata a causa degli avvisi del compilatore. Ovviamente dovresti risolverli per far funzionare correttamente la tua app.
Martin R,

24

Contrariamente alla risposta di Martin, il cast su int (o ignorando l'avvertimento) non è sempre sicuro anche se sai che il tuo array non ha più di 2 ^ 31-1 elementi. Non durante la compilazione per 64 bit.

Per esempio:

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
Hai ragione sul fatto che lanciare il risultato indexOfObject:sarebbe una cattiva idea. La mia risposta era pensata per il codice specifico nella domanda e il countmetodo non può essere restituito NSNotFound. Non ho raccomandato di lanciare per int o ignorare gli avvisi in generale. Scusami se non era chiaro. In effetti il ​​tuo codice di esempio genererebbe un avviso if (i == NSNotFound)se compilato per 64 bit, quindi il problema non passerebbe inosservato.
Martin R

@Adrian: se non ti dispiace, cosa suggerisci a chi lo fa?
moonman239

@ moonman239 In generale, userei una variabile del tipo corretto, se possibile (il primo suggerimento di @ MartinR) invece del casting (il suo secondo). Come sottolinea, il casting è sicuro in questo caso particolare, ma penso che sia una cattiva abitudine entrare, in quanto può avere conseguenze inaspettate (come nel mio esempio). Ho postato perché sono stato morso da questa situazione specifica (anche se questo è un buon punto sull'avviso del compilatore ==, che devo aver perso).
Adrian,

2
penso che il conteggio sarà usato molto più spesso di indexOfObject e gonfiare un for-loop con NSInteger solo per non avere uno stile di codifica "scadente" non ha senso. Dovresti solo guardare indexOfObject e assicurarti di usare NSIntegers lì, tutto ciò che conta semplicemente qualcosa va bene come int, specialmente in un focus sui metodi
NikkyD

5

Cambia chiave in Progetto> Crea impostazione " typecheck chiama a printf / scanf : NO "

Spiegazione : [Come funziona]

Controllare le chiamate a printf e scanf, ecc., Per assicurarsi che gli argomenti forniti abbiano tipi appropriati per la stringa di formato specificata e che le conversioni specificate nella stringa di formato abbiano un senso.

Spero che funzioni

Altro avvertimento

la conversione implicita dell'obiettivo c perde la precisione dei numeri interi da "NSUInteger" (aka "unsigned long") a "int

Modifica chiave " conversione implicita in 32 bit Tipo> Debug> * 64 architettura: No "

[ attenzione: può annullare altri avvisi di conversione dell'architettura a 64 bit] .


se volessi convertire la tua libreria a 32 bit in 64 bit, questa è un'opzione promettente.
San

2

Fare il casting esplicito su "int" risolve il problema nel mio caso. Ho avuto lo stesso problema. Così:

int count = (int)[myColors count];

o si chiama "implicito"? LOL :) In entrambi i casi, ha funzionato.
Vladimir Despotovic,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.