【问题标题】:How does printf handle its arguments?printf 如何处理它的论点?
【发布时间】:2011-01-26 20:36:52
【问题描述】:

printf 如何处理它的参数?我知道在 C# 中我可以使用 params 关键字来做类似的事情,但我无法在 C 中完成它?

【问题讨论】:

    标签: c arguments printf


    【解决方案1】:

    这样的函数称为variadic function。您可以使用... 在 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

    【讨论】:

    • 您的示例是错误的并且不起作用,因为它与 C 语法相矛盾。也许你打错了,忘记了下划线?
    • 另外,提一下#include &lt;stdarg.h&gt;也不错。
    • 正如 psihodelia 所指出的,您仍然缺少几个下划线。该示例无法编译。
    【解决方案2】:

    此功能称为函数中的可变参数数。您必须包含 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
    

    【讨论】:

    • 你的意思是print_arguments(3,1,2,3)
    【解决方案3】:

    在 C 中完成此操作的方式称为“可变参数”。这里有一个教程:http://c-faq.com/~scs/cclass/int/sx11b.html

    【讨论】:

      【解决方案4】:

      正如其他人所说,printf 使用 va_args 来运行。编写自己的 printf 版本是一个非常酷的练习,如果没有其他方法可以验证 printf,与 Pascal 的 writeln 不同,它不是编译器魔法。在你这样做之后,你应该远离它。这是我写的blog article,详细说明了原因(简短的回答是您可以创建可能长时间未被发现的错误)。

      【讨论】:

        【解决方案5】:

        只是为了完成 gcc(不确定其他编译器)支持的故事

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

        允许可变参数宏

        【讨论】:

          【解决方案6】:

          一个与 C 语言中的 printf 相关的答案完整性插件:

          printf&lt;stdio.h&gt;source code为方便起见:

            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 宏清理并结束进程。在概念上类似于内存分配中的“免费”。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-05-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多