警告:“格式不是字符串文字,没有格式参数”

时间:2009-11-05 01:38:29

标签: objective-c warnings string-formatting nslog

自升级到最新的Xcode 3.2.1和Snow Leopard以来,我一直在收到警告

  

“格式不是字符串文字而没有格式参数”

来自以下代码:

NSError *error = nil;

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

}

如果errorMsgFormat是带有格式说明符的NSString(例如:"print me like this: %@"),则上述NSLog调用出了什么问题?什么是修复它的建议方法,以便不生成警告?

11 个答案:

答案 0 :(得分:157)

Xcode抱怨,因为这是一个安全问题。

这里的代码类似于你的代码:

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

最后一个NSLog语句将执行相当于:

NSLog(@"Jon Hess %@");

这将导致NSLog再查找一个字符串参数,但没有一个。由于C语言的工作方式,它会从堆栈中获取一些随机垃圾指针并尝试将其视为NSString。这很可能会导致程序崩溃。现在你的字符串可能没有%@,但有一天他们可能会。您应该始终使用格式字符串和显式控制的数据作为接受格式字符串的函数的第一个参数(printf,scanf,NSLog, - [NSString stringWithFormat:],...)。

正如奥托指出的那样,你应该做的事情可能就是:

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

答案 1 :(得分:112)

您是否正确嵌套括号?我不认为NSLog()喜欢只接受一个论证,这就是你传递的论点。此外,它已经为您进行格式化。为什么不这样做?

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

或者,既然您说errorMsgFormat是一个带有单个占位符的格式字符串,您是否尝试这样做?

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

答案 2 :(得分:38)

最终答案:正如Jon Hess所说,这是一个安全问题,因为您将WHATEVER字符串传递给期望格式字符串的函数。也就是说,它将在所有字符串中评估所有格式说明符。如果没有,真棒,但如果有,可能会发生坏事。

然后,正确的做法是直接使用格式字符串,例如

NSLog(@"%@", myNSString);

这样,即使myNSString中有格式说明符,它们也不会被NSLog评估。

答案 3 :(得分:13)

我不特别推荐使用它,因为警告是一个真正的警告..在动态使用语言时,可以对字符串执行运行时(即插入新信息甚至崩溃程序)。但是,如果你知道它应该是这样的话你可能会强行压制你真的不想被警告它。

#pragma GCC diagnostic ignored "-Wformat-security"

会告诉GCC暂时忽略编译警告..再说一遍,它没有解决任何问题,但有时你可能找不到一个好方法来解决这个问题。

编辑:从clang开始,这个实用语发生了变化。请参阅:https://stackoverflow.com/a/17322337/3937

答案 4 :(得分:10)

最快的解决方法是将@"%@",添加为NSLog来电的第一个参数,即

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

尽管如此,你应该考虑十六奥托的回答。

答案 5 :(得分:10)

我刚刚通过一个零来否定警告,也许这对你有用吗?

NSLog(myString,nil);

答案 6 :(得分:3)

如果你想要一劳永逸地删除警告“格式不是字符串文字而没有格式参数”,你可以在你的目标中禁用GCC警告设置“Typecheck Calls to printf / scanf”(GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO)建立设置。

答案 7 :(得分:2)

NSLog()需要一个格式字符串,传入的内容只是一个字符串。您不需要使用stringWithFormat:,您可以这样做:

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

这会使警告消失。

答案 8 :(得分:2)

FWIW,这也适用于iPhone开发者。我正在编写3.1.3 SDK编码,并遇到同样的错误(在NSLog()中嵌套stringWithFormat)。 Sixten和Jon都有钱。

答案 9 :(得分:0)

只要让任何人知道在NSMutableString上使用appendFormat,如果尝试传入格式化的字符串,也会出现此警告:

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

为避免此警告,请将上述内容改为:

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

更简洁,更安全。享受!

答案 10 :(得分:-2)

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