Передайте вызов функции variadic в C

174
задан nalzok 15 March 2016 в 14:34
поделиться

8 ответов

Если у Вас нет функции аналогичной vfprintf, который берет va_list вместо переменного количества аргументов, Вы не можете сделать этого . См. http://c-faq.com/varargs/handoff.html .

Пример:

void myfun(const char *fmt, va_list argp) {
    vfprintf(stderr, fmt, argp);
}
147
ответ дан Uli Köhler 23 November 2019 в 20:32
поделиться

Не непосредственно, однако это распространено (и Вы найдете почти универсально случай в стандартной библиотеке) для функций variadic для прибытия в пар с varargs функция альтернативы стиля. например, printf / vprintf

v.. функции берут va_list параметр, реализация которого часто делается с компилятором определенное 'макро-волшебство', но Вам гарантируют тот вызов v.. разработайте функцию от функции variadic как это, будет работать:

#include <stdarg.h>

int m_printf(char *fmt, ...)
{
    int ret;

    /* Declare a va_list type variable */
    va_list myargs;

    /* Initialise the va_list variable with the ... after fmt */

    va_start(myargs, fmt);

    /* Forward the '...' to vprintf */
    ret = vprintf(fmt, myargs);

    /* Clean up the va_list */
    va_end(myargs);

    return ret;
}

Это должно дать Вам эффект, который Вы ищете.

, Если Вы рассматриваете запись variadic библиотечной функции, необходимо также полагать, что предоставление доступа к va_list разрабатывает компаньона, как часть библиотеки. Как Вы видите от своего вопроса, это может быть, оказываются полезными для Ваших пользователей.

57
ответ дан ingomueller.net 23 November 2019 в 20:32
поделиться

Поддержки C99 макросы с variadic аргументами ; в зависимости от Вашего компилятора Вы могли бы быть в состоянии объявить макрос, который делает то, что Вы хотите:

#define my_printf(format, ...) \
    do { \
        fprintf(stderr, "Calling printf with fmt %s\n", format); \
        some_other_variadac_function(format, ##__VA_ARGS__); \
    } while(0)

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

46
ответ дан Schwern 23 November 2019 в 20:32
поделиться

Почти, с помощью средств, доступных в <stdarg.h>:

#include <stdarg.h>
int my_printf(char *format, ...)
{
   va_list args;
   va_start(args, format);
   int r = vprintf(format, args);
   va_end(args);
   return r;
}

Примечание, которое необходимо будет использовать vprintf версия, а не плоскость printf. Нет способа непосредственно вызвать variadic функцию в этой ситуации, не используя va_list.

11
ответ дан Greg Hewgill 23 November 2019 в 20:32
поделиться

Используйте vfprintf:

int my_printf(char *fmt, ...) {
    va_list va;
    int ret;

    va_start(va, fmt);
    ret = vfprintf(stderr, fmt, va);
    va_end(va);
    return ret;
}
3
ответ дан Greg Rogers 23 November 2019 в 20:32
поделиться

Нет никакого способа передать такие вызовы функции, потому что единственное местоположение, где можно получить необработанные элементы стека, находится в my_print(). Обычный способ обернуть вызовы как этот состоит в том, чтобы иметь две функции, та, которая просто преобразовывает аргументы в различное varargs структуры и другой, который на самом деле действует на те структуры. Используя такую двойную модель функции, можно (например), перенестись printf() путем инициализации структур в my_printf() с va_start(), и затем передать их vfprintf().

2
ответ дан John Millikin 23 November 2019 в 20:32
поделиться

Извините за вне темы напыщенную речь, но:

метапроблема состоит в том, что интерфейс varargs в C был существенно поврежден с самого начала. Это - приглашение на переполнение буфера и недопустимые доступы памяти, потому что конец списка аргументов не может быть найден без явного сигнала конца (который никто действительно не использует из лени). И это всегда полагалось на тайные определенные для реализации макросы с жизненным va_copy () макрос, только поддерживаемый на [приблизительно 110] архитектура.

1
ответ дан Thorsten79 23 November 2019 в 20:32
поделиться

Да можно сделать это, но это несколько ужасно, и необходимо знать максимальное количество аргументов. Кроме того, если Вы находитесь на архитектуре, куда аргументы не передаются стеку как x86 (например, PowerPC), необходимо будет знать, используются ли "специальные" типы (дважды, плавания, altivec и т.д.) и если так, соглашение с ними соответственно. Это может быть болезненно быстро, но если Вы находитесь на x86 или если исходная функция имеет четко определенный и ограниченный периметр, это может работать. Это все еще будет взлом , использовать его для отладки цели. Не создавайте Вас программное обеспечение вокруг этого. Так или иначе вот рабочий пример на x86:

#include <stdio.h>
#include <stdarg.h>

int old_variadic_function(int n, ...)
{
  va_list args;
  int i = 0;

  va_start(args, n);

  if(i++<n) printf("arg %d is 0x%x\n", i, va_arg(args, int));
  if(i++<n) printf("arg %d is %g\n",   i, va_arg(args, double));
  if(i++<n) printf("arg %d is %g\n",   i, va_arg(args, double));

  va_end(args);

  return n;
}

int old_variadic_function_wrapper(int n, ...)
{
  va_list args;
  int a1;
  int a2;
  int a3;
  int a4;
  int a5;
  int a6;
  int a7;
  int a8;

  /* Do some work, possibly with another va_list to access arguments */

  /* Work done */

  va_start(args, n);

  a1 = va_arg(args, int);
  a2 = va_arg(args, int);
  a3 = va_arg(args, int);
  a4 = va_arg(args, int);
  a5 = va_arg(args, int);
  a6 = va_arg(args, int);
  a7 = va_arg(args, int);

  va_end(args);

  return old_variadic_function(n, a1, a2, a3, a4, a5, a6, a7, a8);
}

int main(void)
{
  printf("Call 1: 1, 0x123\n");
  old_variadic_function(1, 0x123);
  printf("Call 2: 2, 0x456, 1.234\n");
  old_variadic_function(2, 0x456, 1.234);
  printf("Call 3: 3, 0x456, 4.456, 7.789\n");
  old_variadic_function(3, 0x456, 4.456, 7.789);
  printf("Wrapped call 1: 1, 0x123\n");
  old_variadic_function_wrapper(1, 0x123);
  printf("Wrapped call 2: 2, 0x456, 1.234\n");
  old_variadic_function_wrapper(2, 0x456, 1.234);
  printf("Wrapped call 3: 3, 0x456, 4.456, 7.789\n");
  old_variadic_function_wrapper(3, 0x456, 4.456, 7.789);

  return 0;
}

По некоторым причинам, Вы не можете использовать плавания с va_arg, gcc говорит, что они преобразовываются для удвоения, но катастрофические отказы программы. Тот один демонстрирует, что этим решением является взлом и что нет никакого общего решения. В моем примере я предположил, что максимальное количество аргументов равнялось 8, но можно увеличить то число. Обернутая функция также только использовала целые числа, но она работает тот же путь с другими 'нормальными' параметрами, так как они всегда бросают к целым числам. Целевая функция будет знать их типы, но Ваша посредническая обертка не должна. Обертка также не должна знать правильное количество аргументов, так как целевая функция будет также знать это. Чтобы сделать полезную работу (кроме просто входа вызова), вероятно, необходимо будет знать обоих все же.

1
ответ дан user10146 23 November 2019 в 20:32
поделиться
Другие вопросы по тегам:

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