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

フォーマット文字列は、stringWithFormat: または NSLog のように、@"可変引数に置き換えられるフォーマット指定子を持つもの" である必要があります。

@ は、Objective-C のあらゆる場所で特別な意味を持つことに注意してください。コンパイラ指令を示す記号です。コンパイラは、次のトークンで何をすべきかを認識します (それを展開するか、内容を変換し、時には @end のような対になったディレクティブを探します)

于 2013-06-26T14:02:28.930 に答える
-1

@trojanfoeが示唆しているように、警告を抑制するだけでよい解決策かもしれません。理由があって警告が表示されるだけです。

フォーマット文字列が引数の数や型と一致しない場合、実行時にアプリケーションが壊れる可能性があります。@"My output is: %@" などの文字列リテラルとして形式を指定すると、コンパイラが引数の型と数をチェックできるようになります。

書式として文字列変数を使用するのには十分な理由があるかもしれません。ただし、その場合、この種のエラーを回避することに関しては、自分で行う必要があります。

とにかく、文字列リテラルを使用するためにアルゴリズムを再考することをお勧めします。

于 2013-06-26T14:20:36.123 に答える