Функция Variadic без указания количества параметров - PullRequest
0 голосов
/ 07 ноября 2019

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

Я попытался запустить несколько примеров, которые я нашел в Интернете для среднего числа из параметров, а также алгоритм суммирования. (показано ниже).

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

int sum(int count, ...)
{
    va_list args;
    va_start(args, count);
    int total = 0;

    for (int i = 0; i < count; i++) {
        int num = va_arg(args, int);
        total += num;
        printf("Value #%d: %d\n", i, num);
    }

    va_end(args);

    return total;
}

int main()
{
    int result = sum(1, 2, 3, 4, 5);
    printf("The result is: %d\n", result);
}

Код, приведенный выше, печатает только:

Value #0: 2
The result is: 2

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

Мой вопрос здесь заключается в том, как работает printf, если нет необходимости передавать количество аргументов для замены в форматированной строке? Это потому, что за кулисами среда выполнения C считает, сколько спецификаторов формата объявлено в отформатированной строке? Это мое предположение.

Заранее спасибо.

Ответы [ 2 ]

3 голосов
/ 07 ноября 2019

Нет никакого способа узнать, сколько аргументов было фактически предоставлено.

printf() вычисляет это из строки формата. Каждый из % операторов в строке формата соответствует аргументу (это упрощение), он обрабатывает столько аргументов, сколько необходимо для заполнения каждого из них.

Так что если вы напишите:

printf("%d %s\n", intvar, stringvar);

он знает, что должно быть 2 дополнительных аргумента: один для %d и другой для %s.

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

execl("program", "arg0", "arg1", "arg2", (char *)NULL);

execl() обрабатывает аргументы, пока не достигнет значения NULL.

0 голосов
/ 07 ноября 2019

Если вы называете свою переменную функцию следующим образом:

int result = sum(5 /*count*/, 1, 2, 3, 4, 5);

, добавляя начальное значение 5 (число), она будет делать то, что вы ожидаете, но для интереса попробуйте вызвать ее с большейномер (скажем, 6 или 10) и посмотрим, что произойдет. Их легко ошибиться.

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

#include <stdlib.h>
#include <stdarg.h>

void die(const char *format, ...)
{
    va_list args;

    va_start(args, format);
    vprintf(stderr, format, args);
    va_end(args);
    fprintf(stderr, "\n");

    exit(EXIT_FAILURE);
}

и затем помещает это вВаши заголовочные файлы, чтобы использовать его:

extern void die(const char *format, ...)
   __attribute__((noexit))         // function never exits
   __attribute__((printf(1, 2)));  // looks like printf, format is arg1

Теперь вы можете позвонить die("Program failed because %s", reason);, и программа будет работать без особой суеты. А благодаря использованию __attribute__ компилятор (по крайней мере, GNU) знает, как проверить параметры в строке формата.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...