2012-06-15 2 views
2

Я заметил некоторую проблему с va_start, когда вызов последовательно выполняется в двух функциях. Основной пример может быть следующим:C++ Standard Args: несколько вызовов для va_start

std::string format(std::string fmt, ...) 
{ 
    char buf[2000]; 
    va_list aq; 
    va_start(aq, fmt); 
    vsprintf(buf, fmt.c_str(), aq); 
    va_end(aq); 
    return std::string(buf); 
} 
void error(std::string fmt, ...) 
{ 
    va_list ap; 
    va_start(ap, fmt); 
    printf("%s", format(fmt, ap).c_str()); 
    va_end(ap); 
    exit(1); 
} 

int main() 
{ 
    int x = 10; 
    printf("%s", format("Test %d\n", x).c_str()); 
    error("Test %d\n", x); 
} 

производит

Test 10 
Test -1078340156 

кажется, что при использовании функции error аргументы повреждены.

Что было бы правильным способом передать va_list другой функции?

ответ

11

Вы должны передать va_list явно в качестве аргумента. Передача va_list функции, использующей несколько параметров, не «распаковывает» эти параметры. Вместо этого он просто вызывает функцию с двумя параметрами, вторая из которых - va_list. Причина, по которой вы получаете мусор из этой функции, заключается в том, что она пытается интерпретировать этот va_list как один из аргументов printf, вызывая неопределенное поведение.

Вот почему есть такие функции, как vsprintf - это так, что функции, такие как printf или sprintf может внутренне вызвать вспомогательную функцию, чтобы сделать форматирование, учитывая va_list аргументов.

Например:

std::string vformat(std::string fmt, va_list args) { 
    char buf[2000]; 
    vsprintf(buf, fmt.c_str(), args); 
    return std::string(buf); 
} 

void error(std::string fmt, ...) { 
    va_list ap; 
    va_start(ap, fmt); 
    printf("%s", vformat(fmt, ap).c_str()); 
    va_end(ap); 
    exit(1); 
} 

Хотя, что сказал, в C++ вы должны использовать VARIADIC шаблоны, чтобы сделать это, потому что те могут быть переданы правильно, полностью Типобезопасный, и (если вы ее реализации правильно) не рискуют переполнением буфера.

Надеюсь, это поможет!

+0

Точно, что мне нужно, спасибо за объяснение. Примите его, если разрешите. –

Смежные вопросы