Могу ли я изменить список va_list перед его передачей? - PullRequest
6 голосов
/ 03 октября 2011

В моих попытках понять, что я могу и не могу сделать с помощью va_list в (Objective-) C, я натолкнулся на эту маленькую головоломку. Я надеялся создать категорию на NSString, которая в некоторых случаях немного упростит сообщение stringWithFormat:, просто для удовольствия. То, к чему я стремился, было в состоянии использовать реализацию как это:

[@"My %@ format %@!" formattedWith:@"super", @"rocks"];

В надежде получить строку с надписью "My super format rocks!". Моя (неправильная) реализация метода выглядит так:

- (NSString *)formattedWith:(NSString *)arguments, ...
{
    va_list list;
    va_start(list, arguments);
    NSString *formatted = [[[NSString alloc] initWithFormat:self arguments:list] autorelease];
    va_end(list);
    return formatted;
}

Теперь проблема в том, что как только вызывается va_start(), va_list «укорачивается» (из-за отсутствия лучшего слова) и содержит только остальные аргументы (в случае примера только @"rocks" остается, плюс вызывающий объект, который меня не волнует). Поэтому то, что передано в сообщение initWithFormat:, дает неправильный вид результата.

К вопросу. Есть ли способы изменить va_list, прежде чем я передам его в сообщение initWithFormat:, чтобы я мог как-то перенести первый аргумент обратно в список?

Я не ищу итеративный процесс, в котором я сам перебираю va_list, я пытаюсь понять пределы va_list в целом. Спасибо!

1 Ответ

4 голосов
/ 03 октября 2011

va_list не может быть изменено безопасно .Аргумент va_start также требует аргумента для запуска списка, который исключен.Чтобы обойти это, нужно передать дополнительный бесполезный аргумент или использовать переменные макросы.

//Method declaration
-(NSString*)formattedWith:(NSString*)ignored,...;

//Opt 1 (pass anything for first value)
[@"My %@ format %@!" formattedWith:nil, @"super", @"rocks"];

//Opt 2 (create a macro for the arguments)
#define VA_OPT(...) nil, ##__VA_ARGS__ //VARIADIC OPTIONAL
[@"My %@ format %@!" formattedWith:VA_OPT(@"super", @"rocks"];

//Opt 3 (just create a macro for the whole string format)
//Obviously you should just use the NSString method directly before resorting to this
#define FORMATTED_NSSTRING(str, ...) [NSString stringWithFormat:str, ##__VA_ARGS__]
FORMATTED_NSSTRING(@"My %@ format %@!", @"super", @"rocks")
...