Это - странный вопрос, но является там стандартным способом управлять содержанием 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
может использовать.
Ага, как я понимаю, ваша задача - создать новый аргумент va_list
для передачи стандартным функциям vprintf
. Что, в свою очередь, потребует от вас модификации каждого члена списка. Однако, так как для такого списка нет элементарной операции fetch/edit/insert, вы застряли.
Я не вижу никакого способа сделать это. Конечно, можно создать vprintf
, применяя преобразования in situ, по одному аргументу за раз. Мое предложение будет: Реализовать all такие стандартные библиотечные функции -- в любом случае вы пишете обёртки. Это требует некоторой работы, но вы уже делаете часть ее с hc_printf
и т.д., так почему бы не пройти всю дистанцию (и не угадать, что можно сэкономить на вызове функции!).
Вероятно, вы не сможете использовать 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 к следующему аргументу в стеке.