Perché è necessario eseguire il cast di una variabile NSInteger quando viene utilizzata come argomento di formato?


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

Il codice sopra produce un errore:

I valori di tipo 'NSInteger' non devono essere usati come argomenti di formato; aggiungi invece un cast esplicito a 'long'

Il NSLogmessaggio corretto è in realtà NSLog(@"%lg", (long) myInt);. Perché devo convertire il valore intero di myIntin longse desidero visualizzare il valore?


1
@DanielLee, se usi NSLog(@"%ld", (long) myInt);, il longcast è quello di farlo combaciare con il lqualificatore di %ld, ma tutto ciò non è necessario in quanto NSLog(@"%d", myInt);è sufficiente (dato che possiamo vedere che myIntnon lo è long. In conclusione, si lancia myIntse si utilizza un qualificatore lungo in formato stringa, ma non è necessario utilizzare il qualificatore di formato stringa lungo o il longcast qui.
Rob

1
Apparentemente, non è vero che NSLog (@ "% i", myInt); è sufficiente perché visualizzerai il messaggio di errore come ho mostrato sopra.
Daniel Lee,

2
@DanielLee Vedi il commento di Martin R. Hai pubblicato la tua domanda con il tag iOS (dove nonNSInteger è lungo), ma sembra che stai compilando con il target OS X (dove si trova ). NSInteger long
Rob,

Ah! Capisco. Non sapevo che iOS e OSX avrebbero reso NSInteger diverso per bit e tipo.
Daniel Lee,

Risposte:


193

Questo avviso viene visualizzato se si compila su OS X (64 bit), perché su quella piattaforma NSIntegerè definito come longed è un numero intero a 64 bit. Il %iformato, invece, è for int, che è a 32 bit. Quindi il formato e il parametro effettivo non corrispondono in termini di dimensioni.

Poiché NSIntegerè a 32 o 64 bit, a seconda della piattaforma, il compilatore consiglia di aggiungere un cast in longgenerale.

Aggiornamento: poiché iOS 7 supporta anche i 64 bit ora, puoi ricevere lo stesso avviso durante la compilazione per iOS.


1
Ottengo questo errore su iOS 7. Dato che solo l'ultimo iPhone 5S è a 64 bit se lo imposto a lungo causerà qualche problema su dispositivi a 32 bit meno recenti?
Pritesh Desai,

25
@BartSimpson: con un caso esplicito su "long", come in NSLog(@"%ld", (long) myInt), funziona correttamente su 32-bit e 64-bit.
Martin R,

@MartinR se stiamo lanciando, perché non usare solo a lungo in primo luogo?
William Entriken,

3
@FullDecent: Naturalmente si può lavorare con lunghi qui: long myInt = [myNumber longValue];. Ma molti metodi (Core) Foundation utilizzano NS (U) Integer come parametro o valore di ritorno, quindi il problema generale rimane. Inoltre, può avere senso nell'app utilizzare NS (U) Integer per ottenere un intervallo più ampio disponibile su dispositivi a 64 bit.
Martin R,

39

Non è necessario eseguire il cast di nulla se gli identificatori di formato corrispondono ai tipi di dati. Vedi la risposta di Martin R per i dettagli su come NSIntegerviene definito in termini di tipi nativi.

Quindi, per il codice destinato a essere creato per ambienti a 64 bit, è possibile scrivere le istruzioni del registro in questo modo:

NSLog(@"%ld",  myInt); 

mentre per ambienti a 32 bit puoi scrivere:

NSLog(@"%d",  myInt); 

e tutto funzionerà senza cast.

Uno dei motivi per utilizzare i cast è che il buon codice tende a essere portato su piattaforme diverse e, se si lanciano esplicitamente le variabili, verranno compilate in modo pulito sia a 32 che a 64 bit:

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

E nota che questo è vero non solo per le dichiarazioni NSLog, che dopo tutto sono solo strumenti di debug, ma anche per [NSString stringWithFormat:]i vari messaggi derivati, che sono elementi legittimi del codice di produzione.


1
Quindi ora che è richiesto questo hack, è ancora buona norma utilizzare NSInteger in primo luogo?
William Entriken,

@FullDecent È solo un problema nel codice che viene interpretato in fase di esecuzione, come le stringhe di formato. Tutti i codici compilati sfruttano il typedef NSInteger.
Monolo,

Si è delle migliori pratiche da usare NSInteger, perché ci sono buone ragioni per cui si è definito il modo in cui è definito.
gnasher729,

22

Invece di passare un NSInteger a NSLog, basta passare un NSNumber. Questo aggirerà tutti i cast e sceglierà il giusto identificatore di formato stringa.

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

Funziona anche con NSUIntegers senza doversi preoccupare di questo. Vedi la risposta a NSInteger e NSUInteger in un ambiente misto a 64 bit / 32 bit


2
Suppongo che la risposta selezionata sia tecnicamente la migliore risposta alla domanda, ma se vuoi sapere come evitare di lanciare ogni occorrenza e prevenire avvisi, allora trovo che questa sia la soluzione migliore.
Daniel Wood,

0

Tiene gli avvisi durante l'utilizzo NSLog(@"%ld", (long)myInt);, ma interrompe gli avvisi dopo la dichiarazione di modifica long myInt = 1804809223;in iOS 10.


-2

OS X utilizza diversi tipi di dati — NSInteger, NSUInteger, CGFloat e CFIndex — per fornire un mezzo coerente per rappresentare i valori in ambienti a 32 e 64 bit. In un ambiente a 32 bit, NSInteger e NSUInteger sono definiti rispettivamente come int e unsigned int. Negli ambienti a 64 bit, NSInteger e NSUInteger sono definiti rispettivamente long e unsigned long. Per evitare la necessità di utilizzare diversi identificatori di tipo printf a seconda della piattaforma, è possibile utilizzare gli specificatori mostrati in questo collegamento sia per l'ambiente a 32 bit che a 64 bit.

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.