Подтвердить что ты не робот

Заполнение va_list

Есть ли способ создать va_list с нуля? Я пытаюсь вызвать функцию, которая принимает va_list как параметр:

func(void **entry, int num_args, va_list args, char *key); 

... от функции, которая не принимает переменное число аргументов. Единственный способ, которым я могу думать, - создать промежуточную функцию, которая принимает varargs, а затем передает ее va_list, что довольно глупо:

void stupid_func(void **entry, char *key, int num_args, ...) {
    va_list args;
    va_start(args, num_args);

    func(entry, num_args, args, key);

    va_end(args);
}

Есть ли лучший способ? Я не могу изменить подпись func.

4b9b3361

Ответ 1

Это плохая идея, потому что абстракция va_list заключается в том, чтобы скрыть некоторые специфические детали компилятора/архитектуры grim, относящиеся к указателям на стек, а что нет. И это в значительной степени связано с областью функций после инициализации. Если вы намотаете стек и ссылаетесь на предыдущие кадры va_args вне сферы действия, все может пойти не так. Вы можете передать их, но...

ожидать ошибки

Смотрите: http://lists.freebsd.org/pipermail/freebsd-amd64/2004-August/001946.html

Также проверяйте человека (3) va_copy и друзей для более безопасного обращения с va_args и прохождения их.

ИМХО, материал va_args не очень опрятен. Раньше я занимался этим, инициализируя структуры/непрозрачные указатели в куче, а затем используя арифметику указателя для работы с данными. Но это хак и зависит от обстоятельств.

Ответ 2

Я понимаю и соглашаюсь с предупреждениями Aiden - va_list, а друзья опасны, так как они скрывают соглашения о вызове низкого уровня. Но... в этой ситуации я думаю, что у вас нет другого выбора. Поместите функцию static ... в файл .c, чтобы никто не мог ее увидеть, вроде прокси-сервера для функции, которую нужно вызвать, проверить ад из нее и сделать это. Просто убедитесь, что вы не раскрываете переменные аргументы в цепочке вызовов.

Ответ 3

Ваша идея прокси-функции, которая создает va_list, - это правильный способ сделать это. Нет необходимости в том, чтобы этот прокси-сервер имел общий охват. Однако, если вы обнаружите, что прокси-сервер уже существует. Например, во многих реализациях библиотек sprintf() является просто прокси-сервером для vsprintf().

Если вы не хотите привязать свой код к определенному компилятору и целевой платформе, нет лучшего способа. Имена, определенные в <stdarg.h>, предназначены для обеспечения портативного и последовательного интерфейса для поддержки доступа к спискам переменных параметров. Единственный переносимый способ реализации и использования вариационных функций - через этот интерфейс.

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

Ответ 4

В cocoawithlove есть полезное сообщение в блоге, в котором предлагается способ подделать va_list - он блокирует вас до компилятора и специфическое поведение платформы, о чем свидетельствуют другие хорошие ответы здесь.

Ответ 5

Твой stupid_func - это действительно действующий C-код, иначе как вы могли бы называть vprintf и подобные функции?

glib library используют эти обертки широко. Сама спецификация C99 имеет что-то подобное в примерах. Выдержка из раздела 7.19.6.8:

Ниже показано использование функции vfprintf в общей процедуре представления ошибок.

#include <stdarg.h>
#include <stdio.h>
void error(char *function_name, char *format, ...)
{
    va_list args;
    va_start(args, format);
    // print out name of function causing error
    fprintf(stderr, "ERROR in %s: ", function_name);
    // print out remainder of message
    vfprintf(stderr, format, args);
    va_end(args)
}