printf如何处理它的参数?

20

printf如何处理它的参数?我知道在C#中我可以使用params关键字来完成类似的操作,但在C语言中我无法实现,请问该如何解决?

6个回答

21

这样的函数被称为变参函数。在C语言中,您可以使用...来声明一个变参函数,例如:

int f(int, ... );

你可以使用va_startva_argva_end来处理参数列表。这是一个例子:

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

void f(void);

main(){
        f();
}

int maxof(int n_args, ...){
        register int i;
        int max, a;
        va_list ap;

        va_start(ap, n_args);
        max = va_arg(ap, int);
        for(i = 2; i <= n_args; i++) {
            if((a = va_arg(ap, int)) > max)
                max = a;
        }

        va_end(ap);
        return max;
}

void f(void) {
        int i = 5;
        int j[256];
        j[42] = 24;
        printf("%d\n",maxof(3, i, j[42], 0));
}

如需更多信息,请参见The C Bookstdarg.h


2
你的例子是错误的,不起作用,因为它与C语法相矛盾。也许你打错了字,忘记下划线了? - psihodelia
此外,提到 #include <stdarg.h> 会很好。 - David Thornley
你还缺少一些下划线,就像psihodelia指出的那样。这个例子无法编译。 - Thanatos

10

这个功能叫做函数中的可变数量参数。您需要包含stdarg.h头文件,然后在函数体内使用va_list类型和va_startva_argva_end函数:

void print_arguments(int number_of_arguments, ...)
{
  va_list list;
  va_start(list, number_of_arguments);
  printf("I am first element of the list: %d \n", va_arg(list, int));
  printf("I am second element of the list: %d \n", va_arg(list, int));
  printf("I am third element of the list: %d \n", va_arg(list, int));
  va_end(list);
}

然后像这样调用您的函数:

print_arguments(3,1,2,3);

它将打印出以下内容:

    I am first element of the list: 1
    I am second element of the list: 2
    I am third element of the list: 3

2
你是不是想说 print_arguments(3,1,2,3) - bk1e

8

7

像其他人说的那样,printf使用va_args来实现。编写自己的printf版本是一个非常棒的练习,如果没有其他原因的话,可以验证printf不像Pascal的writeln那样是编译器魔法。但是当你完成后,应该离开它。这里有一篇我写的博客文章详细说明了为什么(简短的答案是你可能会创建长时间未被发现的错误)。


6

为了完整地讲述故事,gcc(不确定其他编译器)支持以下内容:

#define FUNC(X,Y,...) wiz(X,Y, ##__VA_ARGS__)

允许可变宏


1

一个与C语言中的printf特别相关的答案完整性附加组件:

<stdio.h>中的printf源代码为方便起见:

  20 #include <libioP.h>
  21 #include <stdarg.h>
  22 #include <stdio.h>
  23 
  24 #undef printf
  25 
  26 /* Write formatted output to stdout from the format string FORMAT.  */
  27 /* VARARGS1 */
  28 int
  29 __printf (const char *format, ...)
  30 {
  31   va_list arg;
  32   int done;
  33 
  34   va_start (arg, format);
  35   done = vfprintf (stdout, format, arg);
  36   va_end (arg);
  37 
  38   return done;
  39 }
  40 
  41 #undef _IO_printf
  42 ldbl_strong_alias (__printf, printf);
  43 /* This is for libg++.  */
  44 ldbl_strong_alias (__printf, _IO_printf);

我们可以看到,上面的答案中描述的模板已经被满足:
  1. 函数声明:...符号强调多个参数作为输入。
  2. va_list变量创建,自动提取“额外”的输入参数。
  3. va_start调用将我们设置在要开始的地址处。
  4. va_arg调用实际使用每个参数。每次调用都会递增到下一个参数。将在vfprintf内部使用。
  5. va_end宏清理并结束过程。概念类似于内存分配中的“free”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接