带有 `fcn( char *, ...)` 的可变参数函数它怎么知道什么时候结束?

variadic functions with `fcn( char *, ...)` how does it know when to end?

我一直在审查来自多个来源的内容,包括我最喜欢的 K&R 第二版。

我一直在研究可变参数函数,我看到的几乎所有教程都在省略号之前使用 and int 来确定传递的变量参数总数。

但是书中的K&R例子没有用int,他们用的是char *

我搜索了 Whosebug,发现了类似的东西:

Any variadic function must have a way for the caller to specify the number and types of arguments. The *printf functions, for example, do so via the (non-variadic) format string.

No -- C doesn't define end as having any special meaning with varargs. When you write a function that takes a variable argument list, it's up to you to decide how to tell it how long of a list has been passed. link

K&R minprintf 旨在展示如何使用可变函数。

---- to show how to write a function that processes a variable-length argument list in a portable way. Since we are mainly interested in the argument processing, minprintf will process the format string and arguments but will call the real printf to do the format conversions

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 不解释。从我在网上阅读的内容和上面的一些引述来看,可变参数函数不知道在哪里结束,除非你告诉它,比如在省略号前加上一个 int。

是的,里面有一个[=11=]。查看循环的终止条件:

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

p不指向[=11=]值时,*p != '[=14=]',即(bool)*ptrue。在这种情况下,*p 被处理,无论是 % 还是其他。

p指向[=11=]值时,(bool)*pfalse。循环结束,va_end 被调用。

因此,在扫描完字符串、处理所有 % 说明符后,它会通过检查 字符串结尾 .

来终止