views:

320

answers:

5

How does 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 ?

+5  A: 

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

Tyler McHenry
+10  A: 

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.

Justin Ethier
Your example is wrong and doesn't work because it contradicts to the C syntax. Maybe you have made a typo and forgot underscore?
psihodelia
In addition, mentioning `#include <stdarg.h>` would be nice.
David Thornley
Fixed, thanks for the feedback.
Justin Ethier
You're still short a few underscores, as psihodelia noted. The example does not compile.
Thanatos
Good point. The example compiles now.
Justin Ethier
+6  A: 

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
psihodelia
Did you mean `print_arguments(3,1,2,3)`?
bk1e
@bk1e: thanks, I've done a typo; have updated
psihodelia
+4  A: 

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

plinth
A: 

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

pm100