Warnung: "Format kein Zeichenfolgenliteral und keine Formatargumente"


110

Seit dem Upgrade auf den neuesten Xcode 3.2.1 und Snow Leopard habe ich die Warnung erhalten

"Format kein String-Literal und keine Formatargumente"

aus dem folgenden Code:

NSError *error = nil;

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

}

Wenn errorMsgFormates sich um ein NSStringFormatformat handelt (z. B. :) "print me like this: %@", was ist mit dem obigen NSLogAufruf falsch ? Und wie kann das Problem behoben werden, damit die Warnung nicht generiert wird?

Antworten:


113

Verschachteln Sie Ihre Klammern richtig? Ich glaube nicht, dass ich NSLog()gerne nur ein Argument nehme, das ist es, woran Sie es weitergeben. Außerdem übernimmt es bereits die Formatierung für Sie. Warum nicht einfach so machen?

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

Oder errorMsgFormatversuchen Sie dies , da Sie sagen, dass es sich um eine Formatzeichenfolge mit einem einzelnen Platzhalter handelt?

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

14
"Ich glaube nicht, dass NSLog () nur ein Argument akzeptiert" NSLog()kann ein Argument annehmen, wenn die Formatzeichenfolge keine Formatspezifizierer enthält.
user102008

Gibt eine weitere Warnung aus. Datenargument wird von Formatzeichenfolge nicht verwendet.
Hasan

157

Xcode beschwert sich, weil dies ein Sicherheitsproblem ist.

Hier ist ein ähnlicher Code wie Sie:

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

Diese letzte NSLog-Anweisung wird das Äquivalent dazu ausführen:

NSLog(@"Jon Hess %@");

Das wird dazu führen, dass NSLog nach einem weiteren String-Argument sucht, aber es gibt keines. Aufgrund der Funktionsweise der C-Sprache wird ein zufälliger Müllzeiger vom Stapel aufgenommen und versucht, ihn wie einen NSString zu behandeln. Dies wird höchstwahrscheinlich Ihr Programm zum Absturz bringen. Jetzt enthalten Ihre Zeichenfolgen wahrscheinlich keine% @, aber eines Tages könnten sie. Sie sollten immer eine Formatzeichenfolge mit Daten verwenden, die Sie explizit als erstes Argument für Funktionen steuern, die Formatzeichenfolgen annehmen (printf, scanf, NSLog, - [NSString stringWithFormat:], ...).

Wie Otto betont, sollten Sie wahrscheinlich nur Folgendes tun:

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

17
Und noch einmal auf SO fallen die detaillierten und guten Antworten auf die Strecke. DANKE, dass Sie dies vollständig erklärt haben. Ich hätte das nie herausgefunden.
Dan Rosenstark

38

Endgültige Antwort: Wie Jon Hess sagte, handelt es sich um ein Sicherheitsproblem, da Sie eine WHATEVER-Zeichenfolge an eine Funktion übergeben, die eine Formatzeichenfolge erwartet. Das heißt, es werden alle Formatbezeichner INNERHALB der beliebigen Zeichenfolge ausgewertet. Wenn es keine gibt, großartig, aber wenn es welche gibt, könnten schlimme Dinge passieren.

Das Richtige ist also, beispielsweise eine Formatzeichenfolge direkt zu verwenden

NSLog(@"%@", myNSString);

Auf diese Weise werden Formatspezifizierer, selbst wenn sie in myNSString vorhanden sind, nicht von NSLog ausgewertet.


13

Ich empfehle dies nicht besonders, da die Warnung eine echte Warnung ist. Bei einer dynamischen Verwendung der Sprache ist es möglich, Dinge zur Laufzeit mit der Zeichenfolge zu tun (dh neue Informationen einzufügen oder sogar das Programm zum Absturz zu bringen). Dies ist jedoch möglich zu unterdrücken erzwingen, wenn Sie wissen, dass es so sein sollte und Sie wirklich nicht davor gewarnt werden wollen ..

#pragma GCC diagnostic ignored "-Wformat-security"

Würde GCC anweisen, die Kompilierungswarnung vorübergehend zu ignorieren. Wiederum löst es nichts, aber es kann vorkommen, dass Sie keinen guten Weg finden, um das Problem tatsächlich zu beheben.

EDIT: Seit dem Klirren hat sich das Pragma geändert. Siehe hierzu: https://stackoverflow.com/a/17322337/3937


10

Der schnellste Weg, dies zu beheben, besteht darin @"%@",, Ihrem NSLogAnruf als erstes Argument hinzuzufügen , d. H.

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

Allerdings sollten Sie wahrscheinlich die Antwort von Sechzehn Otto in Betracht ziehen.


10

Ich habe gerade eine Null übergeben, um die Warnungen zu negieren. Vielleicht würde das für Sie funktionieren?

NSLog (myString, nil);


5
Kann jemand erklären, WARUM das Bestehen von Null als zweites Paramente die Warnung löst?
cprcrack

1
Das Übergeben von nil ist explizit, das Fehlen eines zweiten Parameters jedoch nicht. Sie können davon ausgehen, dass Ihr Kamin beim Verlassen des Hauses nicht beleuchtet war, oder Sie können sicherstellen, dass dies nicht der Fall war. Während normalerweise nichts passiert, weil Sie Ihren Kamin selten benutzen, brennt Ihr Haus einmal nieder.

1
@SoldOutActivist Nicht hilfreich. Der nicht offensichtliche Punkt hier (für jemanden, der nicht aus einem C-Hintergrund stammt) ist, was der Unterschied im Verhalten zwischen dem Übergeben einer expliziten Null und dem Übergeben von nichts ist, und Ihr Kommentar erklärt dies nicht.
Mark Amery

Gut: Alle Obj-C-Methoden, die eine variable Anzahl von Argumenten akzeptieren können, müssen explizit mit Null abgeschlossen werden. Nichts zu bestehen ist nicht dasselbe wie nichts zu bestehen. Verbringen Sie jederzeit mit Obj-C und Sie werden dies immer wieder sehen. Das Erstellen von Arrays ist am häufigsten.

3
Dies kann die Compiler-Warnung stoppen, aber das zugrunde liegende Problem, das von Jon Hess erklärt wurde , besteht weiterhin - wenn mehr als ein Formatbezeichner vorhanden ist myString, ist der erste in Ordnung, aber der zweite nimmt Müll vom Stapel auf. Die Substitutionsliste in NSLog()wird niemals beendet nil , @Sold. Es gibt zwei Möglichkeiten, um herauszufinden, wie lang die Liste der Argumente ist: ein Sentinel-Wert oder was in printf()und in der Familie verwendet wird - ein weiteres Argument, das die Berechnung der Anzahl ermöglicht (z. B. durch Zählen der Formatspezifizierer).
Jscs

3

Wenn Sie die Warnung "Format kein Zeichenfolgenliteral und keine Formatargumente" ein für alle Mal entfernen möchten, können Sie die GCC-Warneinstellung "Typecheck Calls to printf / scanf" (GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO) in den Build-Einstellungen Ihres Ziels deaktivieren.


5
Dadurch wird die Warnung stummgeschaltet, der zugrunde liegende Fehler in Ihrer Anwendung wird jedoch nicht behoben. Wenn Sie die Warnung stumm schalten, ignorieren Sie einen potenziellen Fehler, der Ihre Anwendung zum Absturz bringen könnte, basierend auf den vom Benutzer eingegebenen Daten (oder in diesem Fall der von CoreData generierten Fehlermeldung). Es ist besser, einige der anderen Antworten in dieser Frage zu befolgen, um den Fehler im Quellcode zu beseitigen, durch den die Warnung angezeigt wird.
Christopher Fairbairn

2
Richtig ... Deshalb habe ich "die Warnung loswerden" anstatt "lösen" gepostet.
Aldi

Ich bin auf einen Fall gestoßen, in dem die Uthash-Bibliothek diese Warnung bei Aufrufen der Funktion utstring_printf auslöste. Dies ist daher in Situationen nützlich, in denen die Warnung falsch ist.
Alfwatt

2

NSLog () erwartet eine Formatzeichenfolge. Was übergeben wird, ist nur eine Zeichenfolge. Sie müssen stringWithFormat: nicht verwenden. Sie können einfach Folgendes tun:

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

Und das würde die Warnung verschwinden lassen.


2

FWIW, dies gilt auch für iPhone-Entwickler. Ich codiere gegen das 3.1.3 SDK und habe denselben Fehler mit demselben Problem erhalten (Verschachtelung von stringWithFormat in NSLog ()). Sixten und Jon sind auf dem Geld.


0

appendFormatWenn Sie nur jemanden über die Verwendung von on NSMutableString informieren, kann diese Warnung auch angezeigt werden, wenn Sie versuchen, eine formatierte Zeichenfolge wie folgt zu übergeben:

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

Um diese Warnung zu vermeiden, gehen Sie wie folgt vor:

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

Prägnanter und sicherer. Genießen!


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

1
Die Verwendung stringWithFormatist hier überflüssig, wenn Sie nur tun könntenNSLog(@"%@ %@, %@", errorMsgFormat, error, [error userInfo])
Mark Amery
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.