расширяем va_list переносимо - PullRequest
4 голосов
/ 19 октября 2010

У меня есть сторонняя функция с подписью:

int secretfoo(int numargs, ...);

Я могу вызвать его напрямую, но я действительно хочу обернуть его своей функцией, которая добавляет к нему несколько дополнительных аргументов.

Предположим простой случай целых чисел: я хочу, чтобы вызовы secretfoo(2, 10, 20) были переведены так: когда я вижу аргумент 10, чтобы продублировать его и сделать вызов: secretfoo(3, 10, 10, 20). Я хочу сделать это в обертке:

int foowrapper(int numargs, ...);

Эта оболочка анализирует аргументы и вызывает secretfoo, как описано выше.

Можно ли это сделать в переносном виде с va_list / va_arg и т. Д.? Любой другой путь?

Ответы [ 2 ]

3 голосов
/ 19 октября 2010

Не существует переносимого способа манипулирования аргументами в списке переменных аргументов напрямую, потому что это сильно зависит от платформы, как такие аргументы передаются в функцию.И на большинстве аппаратных архитектур абсолютно невозможно вставить дополнительные аргументы в середину или конец списка.

Если существует практический верхний предел количества аргументов, то это может быть сделаноизвлечение всех аргументов для foowrapper и «ручное» построение нового списка аргументов для вызова secretfoo.Код будет выглядеть примерно так:

int foowrapper(int numarg, ...)
{
  va_list args
  int newargs[numarg*2]; /* worst case allocation */
  int numnewargs = 0;

  /* Extract the arguments */
  va_start(numarg, args);
  for (int i=0; i<numarg; i++)
  {
    newargs[numnewargs++] = va_arg(args, int);

    /* duplicate value 10 as you encounter it */
    if (newargs[numnewargs-1] == 10)
    {
      newargs[numnewargs++] = 10;
    }
  }

  /* Forward to the secretfoo function */
  switch (numnewargs)
  {
  case 0: return secretfoo(0);
  case 1: return secretfoo(1, newargs[0]);
  case 2: return secretfoo(2, newargs[0], newargs[1]);
  /* etc... */
  }
}
2 голосов
/ 19 октября 2010

Боюсь, это нельзя сделать переносимо. stdarg.h "определяет четыре макроса" (последний C стандартный чертеж ): va_start, va_end, va_arg и va_copy. Ни одно из них не может использоваться для преобразования va_list обратно в переменное число значений, кроме одного за другим.

Ваша сторонняя библиотека должна была предоставить функцию vsecretfoo(int, va_list), как стандартная библиотека для этих случаев (vprintf и т. Д.).

...