сцепление вызовов функций - PullRequest
1 голос
/ 14 апреля 2019

A printf вызов функции, подобный функции с переменным числом аргументов, достаточно прост - просто используйте v -версию этих функций (vprintf, vsprintf, CString::FormatV и т. Д.).Но что, если я приковываю вызовы?Вот простой код:

#include <stdarg.h>
#include <iostream>
void direct(const char * _fmt, bool _extra, ...){
    va_list args;
    va_start(args, _extra);

    char ca[200];
    vsprintf(ca, _fmt, args);
    std::cout << ca << std::endl;

    va_end(args);
}

void chained(const char * _fmt, ...){
    va_list args;
    va_start(args, _fmt);
    direct(_fmt, false, args);
    va_end(args);
}

int main(){
    direct("direct works just fine: %d", false, 1);
    chained("indirect produces garbage: %d", 1);
    return 0;
}

Пример вывода следующий:

direct works just fine: 1
indirect produces garbage: 1951661256

Я чувствую, что упускаю что-то очевидное, но до сих пор не могу понять это.Пожалуйста, помогите мне исправить это так, чтобы при вызове direct или chained код работал правильно.

Помечен вопрос как C / C ++, но я предпочитаю ответ C ++ (если есть разница)

Ответы [ 2 ]

5 голосов
/ 14 апреля 2019

Я чувствую, что упускаю что-то очевидное, но до сих пор не могу этого понять

Вы сделали.И это то, с чего вы на самом деле начали: "просто используйте v-версию этих функций" .Причина, по которой эти функции получили v-версию, заключалась в том, чтобы разрешить, как вы это называли, их цепочку.Так что, если вы хотите поддержать его для своей собственной функции, похожей на printf, обязательно следуйте той же практике:

void direct_v(const char * _fmt, bool _extra, va_list args){
    char ca[200];
    vsprintf(ca, _fmt, args);
    std::cout << ca << std::endl;
}

void direct(const char * _fmt, bool _extra...){
    va_list args;
    va_start(args, _extra);
    direct_v(_fmt, _extra, args);
    va_end(args);
}

void chained(const char * _fmt...){
    va_list args;
    va_start(args, _fmt);
    direct_v(_fmt, false, args);
    va_end(args);
}

Хорошее появляющееся свойство разделения direct, подобное тому, что вы получаете лучшее разделениепроблемы.Оболочка выполняет бит, связанный с va_list, а v-функция заботится только о том, что нужно сделать со списком, что позволяет здесь использовать повторно.


Примечание перед редактированием: BTW, если совместимость с C действительно важна, прототипы функций нуждаются в запятой, чтобы отделить последний аргумент от многоточия.Синтаксис, который вы использовали, только C ++.

0 голосов
/ 14 апреля 2019

Вы не можете связывать вызовы с переменными функциями в стиле C.Единственный способ - передать va_list в качестве аргумента.Именно по этой причине необходимо семейство функций v *.

Таким образом, вы пишете свои v * -подобные функции в терминах va_list, а затем оборачивают каждую из них в функцию переменной на основе эллипса.

...