警告:“格式不是字符串文字,也没有格式参数”
自从升级到最新的 Xcode 3.2.1 和 Snow Leopard 以来,我一直收到警告
“格式不是字符串文字,也没有格式参数”
来自以下代码的
NSError *error = nil;
if (![self.managedObjectContext save:&error])
{
NSLog([NSString stringWithFormat:@"%@ %@, %@",
errorMsgFormat,
error,
[error userInfo]]);
}
:如果 errorMsgFormat
是带有格式说明符的 NSString
(例如:“像这样打印我: %@"
),上面的 NSLog
调用有什么问题?建议的修复方法是什么以免生成警告?
Since upgrading to the latest Xcode 3.2.1 and Snow Leopard, I've been getting the warning
"format not a string literal and no format arguments"
from the following code:
NSError *error = nil;
if (![self.managedObjectContext save:&error])
{
NSLog([NSString stringWithFormat:@"%@ %@, %@",
errorMsgFormat,
error,
[error userInfo]]);
}
If errorMsgFormat
is an NSString
with format specifiers (eg: "print me like this: %@"
), what is wrong with the above NSLog
call? And what is the recommended way to fix it so that the warning isn't generated?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
Xcode 正在抱怨,因为这是一个安全问题。
下面是与您的代码类似的代码:
最后一条 NSLog 语句将执行与此等效的操作:
这将导致 NSLog 寻找另一个字符串参数,但没有一个。由于 C 语言的工作方式,它将从堆栈中拾取一些随机垃圾指针,并尝试将其视为 NSString。这很可能会让你的程序崩溃。现在您的字符串中可能没有 %@,但有一天它们可能会。您应该始终使用包含明确控制的数据的格式字符串作为采用格式字符串的函数(printf、scanf、NSLog、-[NSString stringWithFormat:]、...)的第一个参数。
正如奥托指出的那样,你可能应该这样做:
Xcode is complaining because this is a security problem.
Here's code similar to yours:
That last NSLog statement is going to be executing the equivalent of this:
That's going to cause NSLog to look for one more string argument, but there isn't one. Because of the way the C language works, it's going to pick up some random garbage pointer from the stack and try to treat it like an NSString. This will most likely crash your program. Now your strings probably don't have %@'s in them, but some day they might. You should always use a format string with data you explicitly control as the first argument to functions that take format strings (printf, scanf, NSLog, -[NSString stringWithFormat:], ...).
As Otto points out, you should probably just do something like:
您是否正确嵌套括号?我不认为 NSLog() 喜欢只接受一个参数,这就是您传递给它的参数。此外,它已经为您完成了格式化。为什么不直接这样做呢?
或者,既然您说
errorMsgFormat
是带有单个占位符的格式字符串,那么您是否尝试这样做?Are you nesting your brackets correctly? I don't think
NSLog()
likes taking only one argument, which is what you're passing it. Also, it already does the formatting for you. Why not just do this?Or, since you say
errorMsgFormat
is a format string with a single placeholder, are you trying to do this?最终答案:正如 Jon Hess 所说,这是一个安全问题,因为您将 WHATEVER 字符串传递给需要格式字符串的函数。也就是说,它将评估任何字符串内的所有格式说明符。如果没有,那就太好了,但如果有,则可能会发生不好的事情。
那么,正确的做法是直接使用格式字符串,例如
这样,即使 myNSString 中有格式说明符,NSLog 也不会评估它们。
Final answer: As Jon Hess said, it's a security issue because you're passing a WHATEVER string to a function expecting a format string. That is, it'll evaluate all format specifiers WITHIN the whatever string. If there aren't any, awesome, but if there are, bad things could happen.
The proper thing to do, then, is USE a format string directly, for example
That way, even if there are format specifiers in myNSString, they don't get evaluated by NSLog.
我不特别推荐使用这个,因为警告是一个真正的警告..在动态使用该语言时,可以在运行时对字符串执行操作(即插入新信息甚至使程序崩溃)..但是这是可能的如果您知道它应该是这样的并且您真的不想收到警告,则强制抑制。
#pragma GCC Diagnostic Beenigned "-Wformat-security"
会告诉 GCC 暂时忽略编译警告..同样,它并不能解决任何问题,但有时您可能找不到真正解决问题的好方法。
编辑:从 clang 开始,编译指示已经改变。请参阅:https://stackoverflow.com/a/17322337/3937
I don't especially recommend using this, since the warning IS a real warning.. in a dynamic use of the language it's possible to do things runtime to the string (i.e. insert new information or even crash the program).. However it's possible to force suppress if you KNOW that it should be like this and you really don't want to be warned about it..
#pragma GCC diagnostic ignored "-Wformat-security"
Would tell GCC to temporarily ignore the compilation warning.. Again it's not solving anything but there may be times when you can't find a good way to actually fix the problem.
EDIT: As of clang, the pragma has changed. See this: https://stackoverflow.com/a/17322337/3937
解决此问题的最快方法是将
@"%@",
添加为NSLog
调用的第一个参数,即,尽管如此,您可能应该考虑十六奥托的答案。
Quickest way to fix it would be to add
@"%@",
as the first argument to yourNSLog
call, i.e.,Though, you should probably consider Sixteen Otto's answer.
我刚刚传递了一个 nil 来否定警告,也许这对你有用?
NSLog(myString, nil);
I've just been passing a nil to negate the warnings, maybe that would work for you?
NSLog(myString, nil);
如果您想一劳永逸地摆脱警告“格式不是字符串文字且没有格式参数”,您可以在目标的构建设置中禁用 GCC 警告设置“Typecheck Calls to printf/scanf”(GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO)。
If you want get rid of the warning "format not a string literal and no format arguments" once and for all, you can disable the GCC warning setting "Typecheck Calls to printf/scanf" (GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO) in your target's build settings.
NSLog() 需要一个格式字符串,传入的只是一个字符串。您不需要使用 stringWithFormat:,您只需执行以下操作:
NSLog(@"%@ %@, %@", errorMsgFormat, error, [error userInfo])
这将使警告消失离开。
NSLog() expects a format string, what is getting passed in is just a string. You do not need to use stringWithFormat:, you can just do:
NSLog(@"%@ %@, %@", errorMsgFormat, error, [error userInfo])
And that would make the warning go away.
FWIW,这也适用于 iPhone 开发人员。我正在针对 3.1.3 SDK 进行编码,并且遇到了同样的错误和同样的问题(在 NSLog() 中嵌套 stringWithFormat)。 Sixten 和 Jon 很赚钱。
FWIW, this applies to iPhone dev as well. I'm coding against the 3.1.3 SDK, and got the same error with the same problem (nesting stringWithFormat inside NSLog()). Sixten and Jon are on the money.
如果尝试像这样传入格式化字符串,只是让任何人知道在 NSMutableString 上使用
appendFormat
也会导致出现此警告:因此,为了避免此警告,请将上面的内容变成这样:
更简洁、更多安全的。享受!
Just letting anyone know using the
appendFormat
on NSMutableString can also cause this warning to appear if trying to pass in a formatted string like so:So to avoid this warning, turn the above into this:
More concise and more secure. Enjoy!