Depuis la mise à niveau vers la dernière version de Xcode 3.2.1 et Snow Leopard, je reçois cet avertissement.
"format pas un littéral de chaîne et aucun argument de format"
à partir du code suivant:
NSError *error = nil;
if (![self.managedObjectContext save:&error])
{
NSLog([NSString stringWithFormat:@"%@ %@, %@",
errorMsgFormat,
error,
[error userInfo]]);
}
Si errorMsgFormat
est un NSString
avec des spécificateurs de format (par exemple: "print me like this: %@"
), quel est le problème avec l'appel ci-dessus NSLog
? Et quelle est la méthode recommandée pour résoudre le problème afin que l'avertissement ne soit pas généré?
Etes-vous emboîté vos crochets correctement? Je ne pense pas que NSLog()
aime prendre un seul argument, et c'est ce que vous le transmettez. En outre, il fait déjà la mise en forme pour vous. Pourquoi ne pas simplement faire ça?
NSLog(@"%@ %@, %@",
errorMsgFormat,
error,
[error userInfo]);
Ou bien, puisque vous dites que errorMsgFormat
est une chaîne de format avec un seul espace réservé, essayez-vous de le faire?
NSLog(@"%@, %@", [NSString stringWithFormat:errorMsgFormat, error],
[error userInfo]);
Xcode se plaint parce que c'est un problème de sécurité.
Voici un code similaire au vôtre:
NSString *nameFormat = @"%@ %@";
NSString *firstName = @"Jon";
NSString *lastName = @"Hess %@";
NSString *name = [NSString stringWithFormat:nameFormat, firstName, lastName];
NSLog(name);
Cette dernière instruction NSLog va exécuter l'équivalent de ceci:
NSLog(@"Jon Hess %@");
Cela va amener NSLog à rechercher un argument de chaîne supplémentaire, mais il n'y en a pas. En raison du fonctionnement du langage C, il va ramasser un pointeur de mémoire aléatoire de la pile et essayer de le traiter comme une chaîne NSString. Cela plantera probablement votre programme. Maintenant, vos chaînes ne contiennent probablement pas% @, mais elles le seront peut-être un jour. Vous devez toujours utiliser une chaîne de format avec les données que vous contrôlez explicitement comme premier argument des fonctions prenant des chaînes de format (printf, scanf, NSLog, - [NSString stringWithFormat:], ...).
Comme Otto le fait remarquer, vous devriez probablement faire quelque chose comme:
NSLog(errorMsgFormat, error, [error userInfo]);
Réponse finale: Comme Jon Hess l’a dit, c’est un problème de sécurité car vous passez une chaîne WHATEVER à une fonction qui attend une chaîne de format. Autrement dit, tous les spécificateurs de format seront évalués dans la chaîne. S'il n'y en a pas, génial, mais s'il y en a, de mauvaises choses pourraient arriver.
La bonne chose à faire est d'utiliser directement une chaîne de formatage, par exemple
NSLog(@"%@", myNSString);
Ainsi, même s'il existe des spécificateurs de format dans myNSString, ils ne sont pas évalués par NSLog.
Je ne recommande pas particulièrement cela, car l'avertissement IS est un véritable avertissement .. Dans une utilisation dynamique de la langue, il est possible de faire fonctionner les choses à la chaîne (c'est-à-dire insérer de nouvelles informations ou même bloquer le programme) .. Cependant, il est possible de forcer la suppression si vous SAVEZ que cela devrait être ainsi et que vous ne voulez vraiment pas en être averti ..
#pragma GCC diagnostic ignored "-Wformat-security"
Je dirais à GCC d'ignorer temporairement l'avertissement de compilation. Encore une fois, cela ne résout rien, mais il peut arriver que vous ne trouviez pas le meilleur moyen de résoudre le problème.
EDIT: A partir de Clang, le pragma a changé. Voir ceci: https://stackoverflow.com/a/17322337/3937
Je viens de passer un néant pour annuler les avertissements, peut-être que cela fonctionnerait pour vous?
NSLog (myString, nil);
Le moyen le plus rapide de résoudre ce problème consiste à ajouter @"%@",
comme premier argument de votre appel NSLog
, c.-à-d.,
NSLog(@"%@", [NSString stringWithFormat: ....]);
Cependant, vous devriez probablement considérer la réponse de Seize Otto.
Si vous souhaitez vous débarrasser une fois pour toutes de l'avertissement "format pas un littéral de chaîne et pas d'arguments de format", vous pouvez désactiver le paramètre d'avertissement GCC "Appels de type vers printf/scanf" (GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO) dans les paramètres de construction de votre cible.
FWIW, cela s’applique également à l’iPhone dev. Je code avec le SDK 3.1.3 et j'ai la même erreur avec le même problème (imbrication de stringWithFormat dans NSLog ()). Sixten et Jon sont sur l'argent.
NSLog () attend une chaîne de format, ce qui est transmis est simplement une chaîne. Vous n'avez pas besoin d'utiliser stringWithFormat :, vous pouvez simplement faire:
NSLog(@"%@ %@, %@", errorMsgFormat, error, [error userInfo])
Et cela ferait disparaître l'avertissement.
Le simple fait d'informer quiconque d'utiliser appendFormat
sur NSMutableString peut également provoquer l'apparition de cet avertissement si vous essayez de transmettre une chaîne mise en forme de la manière suivante:
NSMutableString *csv = [NSMutableString stringWithString:@""];
NSString *csvAddition = [NSString stringWithFormat:@"%@",WHATEVERYOUAREPUTTINGINYOURSTRING];
[csv appendFormat:csvAddition];
Donc, pour éviter cet avertissement, transformez ce qui précède en ceci:
NSMutableString *csv = [NSMutableString stringWithString:@""];
[csv appendFormat:@"%@",WHATEVERYOUAREPUTTINGINYOURSTRING];
Plus concis et plus sécurisé. Prendre plaisir!