4

我从下一行收到“格式字符串不是字符串文字”警告

NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:valist];

我在以下功能中使用它

- (void)logMessage:(NSString *)format
         level:(LoggingLevel)level
withParameters:(va_list)valist {
         if (level >= self.loggingLevel) {
              NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:valist];        
         } 

知道如何解决这个问题吗?我正在使用 Xcode 4.6.3

4

4 回答 4

11

抑制它使用:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-nonliteral"

- (void)logMessage:(NSString *)format
         level:(LoggingLevel)level
withParameters:(va_list)valist {
         if (level >= self.loggingLevel) {
              NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:valist];        
         } 

#pragma clang diagnostic pop
于 2013-06-26T14:04:53.183 回答
10

如果你告诉编译器你的方法有一个类似格式的参数,使用 NS_FORMAT_FUNCTION宏:

- (void)logMessage:(NSString *)format
         level:(LoggingLevel)level
withParameters:(va_list)valist NS_FORMAT_FUNCTION(1,0) {
         if (level >= self.loggingLevel) {
              NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:valist];        
         } 
}

然后

  • 您方法中的编译器警告消失了,但是
  • 如果您使用不是字符串文字的格式字符串调用方法,则会收到警告。

例子:

NSString *abc = @"foo %@ bar";
[self logMessage:abc level:7 withParameters:NULL];

warning: format string is not a string literal [-Wformat-nonliteral]
[self logMessage:abc level:7 withParameters:NULL];
                 ^~~

补充:这同样适用于您评论中提到的功能。它们也应该被“标记” NS_FORMAT_FUNCTION

+ (void)logVeryFineWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2)
{
    va_list ap;
    va_start(ap, format);
    [[self sharedInstance] logMessage:format level:VERY_FINE withParameters:ap];
    va_end(ap);
}

+ (void)say:(NSString *)formatstring, ... NS_FORMAT_FUNCTION(1,2)
{
    va_list arglist;
    va_start(arglist, formatstring);
    // This is not needed: 
    // NSString *litralString = [NSString stringWithFormat:@"%@",formatstring];
    NSString *statement = [[NSString alloc] initWithFormat:formatstring arguments:arglist];
    va_end(arglist);
    [ModalAlert ask:statement withCancel:@"Okay" withButtons:nil];
}
于 2013-06-26T14:16:45.137 回答
0

格式字符串应该是 @"something with some format specifiers to be replace by the varargs" 就像在 stringWithFormat: 或 NSLog 中一样

请记住,@ 在 Objective-C 中到处都有特殊的含义。它是指示编译器指令的标志。编译器将知道如何处理以下标记(扩展它或转换内容,有时会寻找匹配的配对指令,如 @end

于 2013-06-26T14:02:28.930 回答
-1

正如@trojanfoe 所建议的那样,这可能是您压制警告的正确解决方案。只是警告的存在是有原因的。

如果您的格式字符串与参数的数量和/或类型不匹配,您的应用程序可能会在运行时中断。当您提供格式为字符串文字时,例如 @"My output is: %@" ... 然后您可以使编译器检查参数的类型和数量。

使用字符串变量作为格式可能有充分的理由。但是,在这种情况下,要避免此类错误,您只能靠自己。

无论如何,我建议重新考虑您的算法以支持使用字符串文字。

于 2013-06-26T14:20:36.123 回答