【问题标题】:Warning: Format string is not a string literal [duplicate]警告:格式字符串不是字符串文字 [重复]
【发布时间】:2013-06-26 13:58:25
【问题描述】:

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

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

【问题讨论】:

    标签: ios objective-c clang


    【解决方案1】:

    抑制它使用:

    #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
    

    【讨论】:

      【解决方案2】:

      如果你告诉编译器你的方法有一个类似格式的参数,使用 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];
                       ^~~
      

      添加:这同样适用于您的 cmets 中提到的功能。 他们也应该用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];
      }
      

      【讨论】:

      • +1 比我的回答好
      • @trojanfoe:谢谢!
      • @MartinR 是的,它删除了警告,但正如你上面所说,我在 [[self sharedInstance] logMessage:format level:FINE withParameters:ap] 上收到警告;
      • @AmitVyawahare:你在哪里打电话给[[self sharedInstance] logMessage:format ...?可以显示调用方法吗?
      • + (void)logVeryFineWithFormat:(NSString *)format, ... { va_list ap; va_start(ap, 格式); [[self sharedInstance] logMessage:format level:VERY_FINE withParameters:ap]; va_end(ap); }
      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

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

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

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

        【讨论】:

        • 我不同意;我认为@MartinR 的回答效果最好。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-29
        • 2010-12-13
        • 2011-05-24
        • 2018-09-15
        相关资源
        最近更新 更多