开发者

How does printf handle its arguments?

How d开发者_如何学Coes printf handle its arguments? I know that in C# I can use params keyword to do something similar but I can't get it done in C ?


Such a function is called a variadic function. You may declare one in C using ..., like so:

int f(int, ... );

You may then use va_start, va_arg, and va_end to work with the argument list. Here is an example:

#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));
}

For more information, please see The C Book and stdarg.h.


This feature is called Variable numbers of arguments in a function. You have to include stdarg.h header file; then use va_list type and va_start, va_arg, and va_end functions within the body of your function:

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);
}

Then call your function like this:

print_arguments(3,1,2,3);

which will print out following:

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


The way this is done in C is called "varargs". There's a tutorial for it here: http://c-faq.com/~scs/cclass/int/sx11b.html


Like others have said, printf uses va_args to function. It's a pretty cool exercise to write your own version of printf, if nothing else to verify that printf, unlike Pascal's writeln is not compiler magic. After you do that, you should walk away from it. Here is a blog article I wrote detailing why (the short answer is you can create bugs that may go undetected for a long time).


and just to complete the story gcc (not sure about other compilers) supports

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

to allow variadic macros


An add-on for answer completeness relating specifically to printf in C:

printf <stdio.h> source code for convenience:

  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);

We can see that the template described in above answers is satisfied:

  1. function declaration: ... symbol emphasizes multiple arguments as input.
  2. va_list variable creation, which automatically extracts the 'extra' input arguments .
  3. va_start call which sets us at the address to start from.
  4. va_arg call to actually use each argument. every call increments to the next argument. Will be used inside vfprintf.
  5. va_end macro to clean up and end the process. Similar in concept to 'free' in memory allocation.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜