4

I am getting "Format string is not string literal" warning from following line

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

I using this in following function

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

Any idea how to fix this ? I am using Xcode 4.6.3

rmaddy
  • 314,917
  • 42
  • 532
  • 579
AAV
  • 3,785
  • 8
  • 32
  • 59

4 Answers4

11

Suppress it using:

#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
trojanfoe
  • 120,358
  • 21
  • 212
  • 242
10

If you tell the compiler that your method has a format-like argument, using the NS_FORMAT_FUNCTION macro:

- (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];        
         } 
}

then

  • the compiler warning in your method goes away, but
  • you get a warning if you call your method with a format string which is not a string literal.

Example:

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];
                 ^~~

ADDED: The same applies to the functions mentioned in your comments. They should also be "tagged" with 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];
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • 1
    +1 better than my answer – trojanfoe Jun 26 '13 at 14:18
  • @MartinR yes that removed the warning but as you said above I am getting warning on [[self sharedInstance] logMessage:format level:FINE withParameters:ap]; – AAV Jun 26 '13 at 14:35
  • @AmitVyawahare: Where do you call `[[self sharedInstance] logMessage:format ...` ? Can you show the calling method? – Martin R Jun 26 '13 at 14:40
  • + (void)logVeryFineWithFormat:(NSString *)format, ... { va_list ap; va_start(ap, format); [[self sharedInstance] logMessage:format level:VERY_FINE withParameters:ap]; va_end(ap); } – AAV Jun 26 '13 at 14:47
  • @AmitVyawahare: Then use `NS_FORMAT_FUNCTION` also in the calling method: `+ (void)logVeryFineWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,0) { va_list ap; ...` – Martin R Jun 26 '13 at 14:53
  • @MartinR thank you for the answer but I am getting one more same warning and NS_FORMAT_FUNCTION(1,0) is not helping me. + (void)say:(id)formatstring, ... { va_list arglist; va_start(arglist, formatstring); NSString *litralString = [NSString stringWithFormat:@"%@",formatstring]; id statement = [[NSString alloc] initWithFormat:litralString arguments:arglist]; va_end(arglist); [ModalAlert ask:statement withCancel:@"Okay" withButtons:nil]; } – AAV Jun 26 '13 at 15:52
0

The format string should be @"something with some format specifiers to be replaced by the varargs" just like in stringWithFormat: or in NSLog

Remember that @ has a special meaning everywhere in Objective-C. It is a sigil indicating a compiler directive. The compiler will know what to do with the following token ( expanding it or converting contents, sometimes looking for a matching paired directive like @end

uchuugaka
  • 12,679
  • 6
  • 37
  • 55
-1

It may be the right solutio for you just to suppress the warning, as @trojanfoe suggests. It is just that the warning is there for a reason.

In the event that your format string does not match the number and/or type of your arguments, you application may break on runtime. When you provide the format as string literal such as @"My output is: %@" ... then you enable the compiler to check upon types and numer of arguments.

There may be good reasons for using a string varaible as format. However, in that case you are on your own when it comes to avoiding this type of error.

Anyway, I'd suggest re-thinking your algorithm in favor of using string literals.

Hermann Klecker
  • 14,039
  • 5
  • 48
  • 71