Как установить значение по умолчанию, когда нет дополнительных аргументов, используя va_list в C - PullRequest
4 голосов
/ 13 января 2012

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

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

Ниже приведена более простая версия, использующая аргументы типа int, но принцип того, что я хочу сделать, тот же:

/* appropriate headers... */

void test(int a, ... ) {

   int b;

   va_list args;
   va_start(args,a);

   b = va_arg(args,int);

   if (b == NULL) { // check if no argument is given and set default value
       b = 0; 
   } // if b != NULL then it should be set to the value of the argument
   va_end(args);

   printf("%d %d\n",a,b);
}

int main() {
   test(1);
   test(1,1);
   return 0;
}

Однако, это дает вывод:

1 *random memory address*
1 1

Вывод, который я хочу, должен иметь первую строку как

1 0

Если я не могу использовать этот метод, тогда у кого-нибудь есть идеи, как мне добиться того, чего я хочу? Заранее спасибо.

Ответы [ 3 ]

4 голосов
/ 13 января 2012

Нет способа сделать то, что вы хотите, просто va_list.

Вы можете использовать макросы и __VA_ARGS__, чтобы заставить определенный аргумент отображаться последним в вашем списке аргументов как «терминатор». i.e.:

#define TEST(a, ...) Test(a, __VA_ARGS__, 0)

Обратите внимание, что я использую Visual C ++. Другие компиляторы могут реализовывать __VA_ARGS__ немного по-другому, поэтому вам может потребоваться настроить реализацию.

2 голосов
/ 13 января 2012

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

Вы, кажется, хотите крупного чуда; Извините, доступны только незначительные чудеса.

Вы можете создавать свои интерфейсы следующим образом:

int test1(int x, struct list *list) { ...code to handle adding x to arbitrary list... }

int test0(int x) { return test1(x, &global_struct); }

Затем вы вызываете test0(), если хотите использовать список по умолчанию, и test1(), если хотите указать другой список.

Обратите внимание, что test0() настолько прост, что это хороший кандидат для определения функции C99 inline.

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

1 голос
/ 13 января 2012

Функция должна иметь какой-то способ узнать, сколько аргументов ей дано. Ваша функция не имеет возможности, поэтому она не может работать. Вы можете создать две функции. Вы можете иметь отдельный параметр «количество аргументов». Вы могли бы включить некоторый другой параметр, который косвенно говорит ему, сколько у него параметров (например, printf использует). Но вы должны сделать это как-то.

...