variadic-функции с `fcn (char *, ...)` как он знает, когда заканчивать? - PullRequest
0 голосов
/ 04 февраля 2019

Я просматривал материал из разных источников, включая мой старый любимый второй выпуск K & R.

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

Но пример K & Rв книге не используются int, они используют char *

Я искал stackoverflow и обнаружил такие вещи, как:

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

и

Нет - C не определяет конец как имеющий какое-либо специальное значение с переменными.Когда вы пишете функцию, которая принимает переменный список аргументов, вы сами решаете, как определить, как долго был передан список. ссылка

K & R minprintf предназначен для того, чтобы показать, как использовать переменную функцию.

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

K & R покажет только функцию, я добавил main вснизу, чтобы увидеть, будет ли это работать.Я скомпилировал это с gcc -Wall test.c.Он скомпилирован без предупреждений и работал как ожидалось.Код:

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

/* minprintf: minimal printf with variable argument list */
void minprintf(char *fmt, ...)
{
   va_list ap; /* points to each unnamed arg in turn */
   char *p, *sval;
   int ival;
   double dval;

   va_start(ap, fmt); /* make ap point to 1st unnamed arg */
   for (p = fmt; *p; p++) {
      if (*p != '%') {
         putchar(*p);
         continue;
      }
      switch (*++p) {
      case 'd':
         ival = va_arg(ap, int);
         printf("%d", ival);
         break;
      case 'f':
         dval = va_arg(ap, double);
         printf("%f", dval);
         break;
      case 's':
         for (sval = va_arg(ap, char *); *sval; sval++)
            putchar(*sval);
         break;
      default:
         putchar(*p);
         break;
      }
   }
   va_end(ap); /* clean up when done */
}
// I added this main below to test K&R minprintf function. It compiled no errors and gave right answer.

int main()
{
   int i = 25;
   int j = 21;
   char str[] = "This is a test";
   minprintf("%d, %d, %s\n", i, j, str);
}   

Как minprintf знает, когда закончить?Там есть NULL?K & R не объясняет это.Из материала, который я читаю онлайн, и некоторых из приведенных выше цитат, функция variadic не знает, где заканчиваться, если вы не скажете это, например, с помощью int перед эллипсами.

1 Ответ

0 голосов
/ 04 февраля 2019

Да, там есть \0.Посмотрите на условие завершения цикла:

for (p = fmt; *p; p++) { // look here
    // ...
}

Когда p не указывает на значение \0, *p != '\0', то есть (bool)*p равно true.В этом случае обрабатывается *p, будь то % или что-то еще.

Когда p указывает на значение \0, (bool)*p равно false.Цикл заканчивается, и вызывается va_end.

Поэтому, после того как он отсканировал строку, обработал все % спецификаторы, он завершается проверкой конца строки .

...