Стандартный способ управлять variadic аргументами?

Это - странный вопрос, но является там стандартным способом управлять содержанием a va_list прежде, чем передать его другой функции? Например, предположите, что у меня есть две функции, sum и vsum:

int vsum(int n, va_list ap) {
    int total = 0;
    for (int i = 0; i < n; ++i) {
        total += va_arg(n, int);
    return total;
}

int sum(int n, ...) {
    va_list ap;
    va_start(ap, n);
    int total = vsum(n, ap);
    va_end(ap);
    return total;
}

Если я звоню sum как sum(4, 1, 2, 3, 4), Я ожидаю получать результат 10. Теперь давайте предположим это вместо вызова vsum непосредственно, sum вызывает промежуточную функцию, vsum_stub который делает следующее:

int vsum_stub(int n, va_list ap) {
    va_list temp_ap;
    va_copy(temp_ap, ap);
    for (int i = 0; i < n; ++i) {
        int *arg = &va_arg(ap, int);
        *arg += 2;
    }
    va_end(temp_ap);
    return vsum(n, ap);
}

Теперь, когда я звоню sum(4, 1, 2, 3, 4), Я должен возвратить результат 20 с тех пор vsum_stub инкременты все значения в va_list 2. Это не компилирует, конечно, так как Вы не можете взять адрес результата va_arg. Там другой путь состоит в том, чтобы сделать это хотя? Я работаю в C99.


Фон:

Я работаю над библиотекой, которая делает некоторый перевод указателя так, чтобы данные могли храниться на "куче" в более эффективном формате. Программы компилируются с пользовательским преобразованием, которое преобразовывает вызовы в библиотечные функции как printf к моим собственным интерфейсным функциям (например, hc_printf). hc_printf потребности перевести любые аргументы указателя (строки, предназначенные для %s) прежде, чем передать аргументы реальному printf функция.

Править: Вот пример кода. Скажем, у нас есть строка foo. foo динамично выделяется с измененной версией malloc который возвращает поддельный указатель. Компилятор изменяет программу так, чтобы это могло иметь дело с поддельными указателями. Таким образом, это работает:

char *foo = fake_malloc(4);
fake_strcpy(foo, "foo");

Я хочу записать a fake_vprintf функционируйте как это (в псевдокоде):

int fake_vprintf(const char *format, va_list args) {
    for each pointer argument p in args
        translate p to q, a real pointer to contiguous memory
        replace p with q in args
    }
    return vprintf(format, args);
}

Программа звонила бы fake_vprintf точно так же, как оригинал vprintf использование поддельного указателя. fake_vprintf переводит поддельный указатель на реальный указатель что реальное vprintf может использовать.

7
задан Jay Conrod 5 February 2010 в 21:33
поделиться

2 ответа

Ага, как я понимаю, ваша задача - создать новый аргумент va_list для передачи стандартным функциям vprintf. Что, в свою очередь, потребует от вас модификации каждого члена списка. Однако, так как для такого списка нет элементарной операции fetch/edit/insert, вы застряли.

Я не вижу никакого способа сделать это. Конечно, можно создать vprintf, применяя преобразования in situ, по одному аргументу за раз. Мое предложение будет: Реализовать all такие стандартные библиотечные функции -- в любом случае вы пишете обёртки. Это требует некоторой работы, но вы уже делаете часть ее с hc_printf и т.д., так почему бы не пройти всю дистанцию (и не угадать, что можно сэкономить на вызове функции!).

2
ответ дан 7 December 2019 в 12:19
поделиться

Вероятно, вы не сможете использовать va_list независимо от платформы. Вам нужно будет посмотреть, как ваша среда определяет va_list в stdarg.h, а затем написать свои собственные инструменты для работы с ним.

Например, если va_list - это просто (char *), вы можете делать с ним все, что угодно.

// add 1000 to the integer stored on the stack and advance va_list
*(int *)va_list += 1000;
va_list += sizeof(int);

Вы говорите компилятору, что хотите, чтобы он считал va_list указателем на int (через int * cast), затем берете значение (*) и прибавляете к нему 1000 (+ = 1000). Теперь переместите указатель va_list к следующему аргументу в стеке.

3
ответ дан 7 December 2019 в 12:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: