2009-11-05 7 views
106

Poiché l'aggiornamento alla più recente Xcode 3.2.1 e Snow Leopard, Sono stato sempre l'avvertimentoAttenzione: "formato non una stringa letterale e senza argomenti formato"

formato

" Non una stringa letterale e non argomenti formato"

dal codice seguente:

NSError *error = nil; 

if (![self.managedObjectContext save:&error]) 
{ 
    NSLog([NSString stringWithFormat:@"%@ %@, %@", 
     errorMsgFormat, 
     error, 
     [error userInfo]]);  

} 

If errorMsgFormat è un NSString con identificatori di formato (es: "print me like this: %@"), cosa c'è di sbagliato con la precedente chiamata NSLog? E qual è il modo consigliato per risolverlo in modo che l'avviso non venga generato?

risposta

109

Stai annidando correttamente le parentesi? Non penso che ai NSLog() piaccia prendere solo un argomento, che è ciò che stai passando. Inoltre, fa già la formattazione per te. Perché non farlo?

NSLog(@"%@ %@, %@", 
    errorMsgFormat, 
    error, 
    [error userInfo]);    

Oppure, dal momento che si dice errorMsgFormat è una stringa di formato con un singolo segnaposto, stai cercando di fare questo?

NSLog(@"%@, %@", [NSString stringWithFormat:errorMsgFormat, error], 
    [error userInfo]);    
+14

"Non credo che a NSLog() sia piaciuto prendere un solo argomento" 'NSLog()' può accettare un argomento, quando la stringa di formato non contiene specificatori di formato. – user102008

+0

Fornisce un altro avviso Argomento dati non utilizzato dalla stringa di formato. – hasan83

10

modo più veloce per risolvere il problema sarebbe di aggiungere @"%@", come primo argomento al NSLog chiamata, vale a dire,

NSLog(@"%@", [NSString stringWithFormat: ....]); 

Anche se, probabilmente si dovrebbe prendere in considerazione la risposta di Sedici Otto.

2

NSLog() si aspetta una stringa di formato, ciò che viene passato è solo una stringa. Non è necessario utilizzare stringWithFormat :, solo si può fare:

NSLog(@"%@ %@, %@", errorMsgFormat, error, [error userInfo])

E che renderebbe l'avvertimento andare via.

155

Xcode si lamenta perché questo è un problema di sicurezza.

Ecco il codice simile al tuo:

NSString *nameFormat = @"%@ %@"; 
NSString *firstName = @"Jon"; 
NSString *lastName = @"Hess %@"; 
NSString *name = [NSString stringWithFormat:nameFormat, firstName, lastName]; 
NSLog(name); 

Quest'ultima affermazione NSLog sta per essere eseguendo l'equivalente di questo:

NSLog(@"Jon Hess %@"); 

che sta per causare NSLog cercare un altro argomento stringa ma non ce n'è uno A causa del modo in cui il linguaggio C funziona, raccoglierà un puntatore casuale dalla pila e cercherà di trattarlo come un NSString. Questo molto probabilmente causerà il crash del tuo programma. Ora le tue stringhe probabilmente non hanno% @ 's in loro, ma un giorno potrebbero. Si dovrebbe sempre usare una stringa di formato con i dati che si controllano esplicitamente come primo argomento delle funzioni che accettano le stringhe di formato (printf, scanf, NSLog, - [NSString stringWithFormat:], ...).

Come Otto fa notare, si dovrebbe probabilmente solo fare qualcosa di simile:

NSLog(errorMsgFormat, error, [error userInfo]); 
+17

E ancora una volta su SO, le risposte dettagliate e buone cadono sul ciglio della strada. GRAZIE per aver spiegato tutto questo. Non l'avrei mai capito. –

2

Se si vuole sbarazzarsi del avvertimento "formato non una stringa letterale e senza argomenti formato" una volta per tutte, si può disabilita l'impostazione di avviso GCC "Typecheck Calls to printf/scanf" (GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO) nelle impostazioni di costruzione del target.

+5

Questo silente l'avviso, ma non farà nulla per correggere il difetto sottostante all'interno dell'applicazione.Riducendo l'avviso si ignora un potenziale bug che potrebbe causare il crash dell'applicazione in base ai dati immessi dall'utente (o in questo caso il messaggio di errore generato da CoreData). È consigliabile seguire alcune delle altre risposte all'interno di questa domanda per rimuovere il bug all'interno del codice sorgente che causa l'avviso. –

+2

Vero ... Ecco perché ho pubblicato "sbarazzarsi dell'avviso" invece di "risolvere". – aldi

+0

Mi sono imbattuto in un caso in cui la libreria uthash stava attivando questo avviso per le chiamate alla sua funzione utstring_printf, quindi è utile in situazioni in cui l'avviso è sbagliato. – alfwatt

10

Ho appena passato un nulla per negare gli avvisi, forse avrebbe funzionato per te?

NSLog (myString, nil);

+5

Qualcuno può spiegare PERCHÉ passare nil come secondo paramente risolve l'avvertimento? – cprcrack

+1

Il passaggio nil è esplicito mentre la mancanza di un secondo parametro non lo è. Puoi presumere che il tuo caminetto non fosse acceso quando sei uscito di casa o puoi assicurarti che non lo fosse. Mentre di solito non succede nulla perché raramente usi il tuo caminetto, sarà quella volta in cui la tua casa brucia. –

+1

@SoldOutActivist Unhelpful. Il punto non ovvio qui (a qualcuno che non viene da uno sfondo C) è ciò che la differenza di comportamento è tra passare un nil esplicito e non passare nulla, e il tuo commento non lo spiega. –

2

FWIW, questo vale anche per iPhone dev. Sto codificando con l'SDK 3.1.3 e ho ottenuto lo stesso errore con lo stesso problema (nesting stringWithFormat all'interno di NSLog()). Sixten e Jon sono in the money.

37

Risposta finale: come ha detto Jon Hess, si tratta di un problema di sicurezza perché si passa una stringa WHATEVER a una funzione che si aspetta una stringa di formato. Vale a dire, valuterà tutti gli specificatori di formato ENTRO la stringa qualunque. Se non ce ne sono, fantastico, ma se ci sono, potrebbero accadere cose brutte.

La cosa giusta da fare, quindi, è quello di utilizzare una stringa di formato direttamente, ad esempio

NSLog(@"%@", myNSString); 

In questo modo, anche se ci sono indicatori di formato in myNSString, essi non vengono valutati da NSLog.

13

Non consiglio particolarmente l'utilizzo di questo, poiché l'avvertimento è un vero avvertimento .. in un uso dinamico del linguaggio è possibile fare cose runtime alla stringa (cioè inserire nuove informazioni o addirittura arrestare il programma). . Tuttavia è possibile forzare sopprimere se si sa che dovrebbe essere così e davvero non si desidera ricevere notifiche su di esso ..

#pragma GCC diagnostic ignored "-Wformat-security"

direbbe GCC di ignorare temporaneamente l'avviso di compilazione .. Ancora una volta non risolve nulla, ma ci possono essere momenti in cui non riesci a trovare un buon modo per risolvere il problema.

MODIFICA: A partire da clang, il pragma è cambiato. Vedere questo: https://stackoverflow.com/a/17322337/3937

-2
NSLog(@"%@ %@, %@", 
     errorMsgFormat, 
     error, 
     [error userInfo]); 
+1

L'uso di 'stringWithFormat' è ridondante qui quando si può semplicemente fare' NSLog (@ "% @% @,% @", errorMsgFormat, error, [error userInfo]) ' –

0

Basta lasciare che qualcuno sa usare la appendFormat su NSMutableString può anche causare questo avviso a comparire se cercando di passare in una stringa formattata in questo modo:

NSMutableString *csv = [NSMutableString stringWithString:@""]; 
NSString *csvAddition = [NSString stringWithFormat:@"%@",WHATEVERYOUAREPUTTINGINYOURSTRING]; 
[csv appendFormat:csvAddition]; 

Quindi, per evitare questo avviso , gira il sopra in questo:

NSMutableString *csv = [NSMutableString stringWithString:@""]; 
[csv appendFormat:@"%@",WHATEVERYOUAREPUTTINGINYOURSTRING]; 

Più conciso e più sicuro. Godere!