Identificatore NSLog / printf per NSInteger?


131

A NSIntegerè 32 bit su piattaforme a 32 bit e 64 bit su piattaforme a 64 bit. Esiste un NSLogidentificatore che corrisponde sempre alla dimensione di NSInteger?

Impostare

  • Xcode 3.2.5
  • compilatore llvm 1.6 (questo è importante; gcc non lo fa)
  • GCC_WARN_TYPECHECK_CALLS_TO_PRINTF acceso

Questo mi sta causando un po 'di dolore qui:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    @autoreleasepool {
        NSInteger i = 0;
        NSLog(@"%d", i);
    }
    return 0;
}

Per il codice a 32 bit, ho bisogno %ddell'identificatore. Ma se uso l' %didentificatore, ricevo un avviso durante la compilazione per 64 bit che suggerisce di utilizzare %ldinvece.

Se uso %ldper abbinare la dimensione a 64 bit, durante la compilazione per il codice a 32 bit ricevo un avviso che suggerisce di usare %dinvece.

Come posso risolvere entrambi gli avvisi contemporaneamente? C'è uno specificatore che posso usare che funziona su entrambi?

Anche questo ha un impatto [NSString stringWithFormat:]e [[NSString alloc] initWithFormat:].

Risposte:


296

Risposta aggiornata:

È possibile utilizzare i modificatori ze tper gestire NSIntegere NSUIntegersenza avvisi, su tutte le architetture.

Si desidera utilizzare %zdper firmato, %tuper non firmato e %txper esadecimale.

Questa informazione viene gentilmente concessa da Greg Parker .


Risposta originale:

L' approccio ufficiale raccomandato è quello di utilizzare %ldcome identificatore e di lanciare l'argomento effettivo in a long.


6
Questa è sicuramente la strada da percorrere, ma penso che potrei usare static inline NSIntToLong(NSInteger i) {return (long)i;}. Questo evita di disabilitare completamente il controllo del tipo (cioè se il tipo di i cambia).
Steven Fisher,

3
Buona idea di @ steven-fisher. Evita di avvertire con:static inline long NSIntToLong(NSInteger i) {return (long)i;}
Erik,

3
È inoltre possibile creare un numero NSN e registrarlo. NSLog(@"%@",@(mynsint)); stackoverflow.com/questions/20355439/...
orkoden

2
@KevinBallard Questo non dovrebbe essere un grave problema di prestazioni. In ogni caso non dovresti usare un sacco di NSLog nel codice di produzione. Se devi registrare molte cose per qualche motivo, fallo su un thread separato.
orkoden,

4
A partire da Xcode 9.3 è presente un avviso quando si utilizza NSInteger come argomento di formato con %zd:Values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead
Rob MacEachern

2

La risposta accettata è assolutamente ragionevole, è conforme agli standard e corretta. L'unico problema è che non funziona più, il che è completamente colpa di Apple.

Il formato% zd è il formato standard C / C ++ per size_t e ssize_t. Come NSInteger e NSUInteger, size_t e ssize_t sono a 32 bit su un sistema a 32 bit e 64 bit su un sistema a 64 bit. Ed è per questo che la stampa di NSInteger e NSUInteger usando% zd ha funzionato.

Tuttavia, NSInteger e NSUInteger sono definiti come "long" su un sistema a 64 bit e come "int" su un sistema a 32 bit (che è 64 vs 32 bit). Oggi, size_t è definita "lunga" a tutti i sistemi, che è la stessa dimensione NSInteger (64 o 32 bit), ma un tipo diverso. O gli avvisi di Apple sono cambiati (quindi non consente il passaggio del tipo sbagliato a printf, anche se ha il giusto numero di bit), oppure sono cambiati i tipi sottostanti per size_t e ssize_t. Non so quale, ma% zd ha smesso di funzionare qualche tempo fa. Oggi non esiste un formato che stamperà NSInteger senza preavviso su entrambi i sistemi a 32 e 64 bit.

Sfortunatamente, l'unica cosa che puoi fare sfortunatamente: usa% ld e trasmetti i tuoi valori da NSInteger a long o da NSUInteger a unsigned long.

Una volta che non costruisci più per 32 bit, puoi semplicemente usare% ld, senza alcun cast.


0

I formatter provengono dalla funzione di stampa standard UNIX / POSIX. Utilizzare % lu per unsigned long long ,% ld per long,% lld per long long e % llu per unsigned long long . Prova man printf sulla console, ma su Mac è incompleto. Le manpage di Linux sono più esplicite http://www.manpages.info/linux/sprintf.3.html

Entrambi gli avvisi possono essere risolti solo da NSLog (@ "% lu", (unsigned long) arg); combinato con un cast in quanto il codice verrà compilato in 32 e 64 bit per iOS. Altrimenti ogni compilation crea un avviso separato.

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.