What's the proper way to wrap [NSString stringWithFormat:]?

nsstring, objective-c

Solution

I think what you want is something like:

+ (NSString *) myFormattedString:(NSString *)format, ... {
  va_list args;
  va_start(args, format);
  NSString *str = [[[NSString alloc] initWithFormat:format arguments:args] autorelease];
  va_end(args);
  return [NSString stringWithFormat:@"Foo: %@.", str];
}

The `stdarg.h` `va_`* macros are used when a function (or, in this case, method) takes a variable number of arguments, as specified by "`...`". `va_start()` is used to find the start of where the variable number of arguments begins. As such, it needs to know a functions/methods last argument (the one just before the "`...`") in order to determine where the variable number of arguments starts. This is a somewhat simplified explanation since what actually happens under the hood is very ABI/Compiler specific. The most important point is that the second argument to `va_start()` is always the name of the variable 'just before the "`...`"'.

`va_end()` should be "called" (it's really a macro, not a function) for maximum portability. Again, this whole variable arguments thing is deep, deep black magic. Depending on the specifics of the compiler and ABI, `va_end()` may not do anything at all. On the other hand, failure to use `va_end()` may cause your program to crash when the `return` statement is reached because the stack frame (if there even is one) is no longer properly set up to actually perform a return.

Problem

Assume I have a method with the signature: ``` + (NSString *) myFormattedString:(NSString *)format, ...; ``` And I want it to prepend a string of my choice (e.g. @"Foo: "). I guess the best way is to use [myString initWithFormat:arguments:], but how would you implement this method? I tried doing the following, but I get the warning as specified in the comment: ``` + (NSString *) myFormattedString:(NSString *)format, ... { char *buffer; [format getCString:buffer maxLength:[format length] encoding:NSASCIIStringEncoding]; va_list args; va_start(args, buffer); // WARNING: second parameter of 'va_start' not last named argument NSString *str = [[NSString alloc] initWithFormat:format arguments:args]; [str autorelease]; return [NSString stringWithFormat:@"Foo: %@.", str]; } ``` The reason I'm assuming va_start() can take in a (char *) is because of the example I saw on the manual page of STDARG(3). Feel free to completely rewrite the method if I'm doing it totally wrong.

Original source