自升级到最新的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
调用有什么问题?什么是修复它的建议方法,以便不生成警告?
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]);
你正确地嵌套括号吗?我不认为NSLog()
喜欢只拿一个论点,这就是你传递的.此外,它已经为您进行格式化.为什么不这样做呢?
NSLog(@"%@ %@, %@", errorMsgFormat, error, [error userInfo]);
或者,既然你说errorMsgFormat
是一个带有单个占位符的格式字符串,你试图这样做吗?
NSLog(@"%@, %@", [NSString stringWithFormat:errorMsgFormat, error], [error userInfo]);
最后的答案:正如Jon Hess所说,这是一个安全问题,因为你将WHATEVER字符串传递给期望格式字符串的函数.也就是说,它将在所有字符串中评估所有格式说明符.如果没有,真棒,但如果有,可能会发生坏事.
那么,正确的做法就是直接使用格式字符串
NSLog(@"%@", myNSString);
这样,即使myNSString中有格式说明符,它们也不会被NSLog评估.
我不特别推荐使用它,因为警告是一个真正的警告..在动态使用该语言时,可以对字符串执行运行时(即插入新信息甚至使程序崩溃)..但是它可能如果你知道它应该像这样强制抑制你真的不想被警告它...
#pragma GCC diagnostic ignored "-Wformat-security"
会告诉GCC暂时忽略编译警告..再次它没有解决任何问题,但有时候你找不到一个好方法来解决问题.
编辑:从铿锵来看,这个实用主义已经改变了.请参阅:https://stackoverflow.com/a/17322337/3937
解决它的最快方法是添加@"%@",
作为NSLog
调用的第一个参数,即
NSLog(@"%@", [NSString stringWithFormat: ....]);
虽然,你应该考虑十六奥托的回答.
我刚刚通过一个零否定警告,也许这对你有用吗?
NSLog(myString,nil);