Thread: Variable Arguments Question

  1. #1
    Registered User moonwalker's Avatar
    Join Date
    Jul 2002
    Posts
    282

    Variable Arguments Question

    I was just playing with Variable Arguments in C.
    I wrote a function that keeps adding the numbers
    (till you get a zero in the argument of the function)

    Here's something I couldn't figure out:

    The following code works :
    Code:
    #include <stdio.h>
    #include <stdarg.h>
    
    void add(char *say, ...)
    {
    	int answer = 0;
    	int temparg = 0;
    
    	va_list argumentlist;
    	va_start(argumentlist, say);
    	
    
    	while ((temparg = va_arg(argumentlist, int)) != 0)
    	{
    		answer = answer + temparg;
    		printf("temparg is %d\n", temparg);
    	}
    
    	
    	printf("%s %d\n", say, answer);
    	va_end(argumentlist);
    }
    
    main()
    {
    
    	add("Addition result: ", 1, 0);
    	add("Addition result: ", 1, 2, 0);
    	add("Addition result: ", 1, 2, 3, 0);
    }
    but this one doesn't :
    Code:
    #include <stdio.h>
    #include <stdarg.h>
    
    void add(char *say, ...)
    {
    	int answer = 0;
    	int temparg = 0;
    
    	va_list argumentlist;
    	va_start(argumentlist, say);
    	
    
    	while (va_arg(argumentlist, int) != 0)
    	{
    		temparg = va_arg(argumentlist, int);
    		answer = answer + temparg;
    		printf("temparg is %d\n", temparg);
    	}
    
    	
    	printf("%s %d\n", say, answer);
    	va_end(argumentlist);
    }
    
    main()
    {
    
    	add("Addition result: ", 1, 0);
    	add("Addition result: ", 1, 2, 0);
    	add("Addition result: ", 1, 2, 3, 0);
    }
    The only difference is in the while loop condition..
    what could the reason be ?

    Also, although I read the same paragraph several times,
    I still didn't understand the real purpose of
    va_list
    va_start
    va_end

    if I say, va_list mahurshi
    does it mean that "mahurshi" is like an array ?
    why do we need to va_end ?

    Thanks for your time and patience in reading this!





    ------------------------------------------------------------------------
    If anyone is too proud to answer my questions politely,
    I encourage him/her not to answer. No offence. Thanks.
    ------------------------------------------------------------------------

  2. #2
    Registered User moi's Avatar
    Join Date
    Jul 2002
    Posts
    946
    in the second one, you call va_arg in the while statement and discard the result, then you call va_arg again inside the while loop and use the result, so you're missing every other arg
    hello, internet!

  3. #3
    Just because ygfperson's Avatar
    Join Date
    Jan 2002
    Posts
    2,490
    variable length functions are interesting, but difficult at times. while most functions store their variables into stack, with the function parameters to show what and where the data is, variable list arguments are different. variable list argument functions don't necessarily know what data they're receiving ahead of time, so they need a pointer (va_list) to the stack so they can manage it during run-time. va_start moves the pointer to the beginning of the list. va_end destroys the list.
    Code:
    arg_type va_arg(va_list, arg_type);
    va_arg takes the next argument, and returns it according to the arg_type you put in. va_arg also goes to the next argument.

    Code:
    while ((temparg = va_arg(argumentlist, int)) != 0)
    	{
    		answer = answer + temparg;
    		printf("temparg is %d\n", temparg);
    	}
    in this one you call va_arg once per iteration.
    Code:
    while (va_arg(argumentlist, int) != 0)
    	{
    		temparg = va_arg(argumentlist, int);
    		answer = answer + temparg;
    		printf("temparg is %d\n", temparg);
    	}
    in this one you call va_arg twice per iteration (once to check if it's equal to 0, and again to get temparg). so your problem is that you're skipping one value per every iteration, which means the values are added wrong, and which also could mean that your program doesn't end correctly until some random 0 is found.

    if I say, va_list mahurshi
    does it mean that "mahurshi" is like an array ?
    not really. let's say you have this function:
    Code:
    void func1(int x, int y);
    the function's stack looks like this:
    Code:
    --------
    - int x-
    -------- 
    - int y-
    --------
    your compiler can determine these 4 byte blocks of memory by checking your function. in a variable argument function, it looks like this:
    Code:
    void printf(char*,...);
    the stack:
    Code:
    ----------
    - char * -
    ----------
    -  ????  -
    the ???? is the data you passed through the function. if you passed an int, a char, and a string pointer, you would have 3 4-byte blocks of memory after that. (note that all variables in a variable length function are promoted, so a char takes up 4 bytes here)

    the only way the compiler can tell the contents of that mystery area is to rely on the programmer to figure out a system. in your function, you keep adding each 4-byte block as if it were an integer until you reach a zero. printf relies on the string to find out what data was handed to it.

    to make a long story short (too late)...
    va_list is a pointer to the beginning of the stack. va_arg takes an argument of the size you specify and increments the pointer to the next argument. va_end disables the va_list pointer so it can't be used (unless va_start is called again). va_start points the va_list to the first element in the stack.

    i know i haven't made it clear, but read through and ask if you need anything clarified.

  4. #4
    Registered User moonwalker's Avatar
    Join Date
    Jul 2002
    Posts
    282

    thanks

    thank you very much.
    that clears up most of my stack
    just kidding..

    it was very helpful. thanks once again.

  5. #5
    Registered User moonwalker's Avatar
    Join Date
    Jul 2002
    Posts
    282

    oh

    oh, another question...
    i want
    void add(char *say, ...)

    to be directly
    void add(...)

    is that possible ?

    also, i am terminating with a zero in my code... i want it to
    terminate after the last argument (it need not be zero)
    how can it be done ?

    thanks again

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > void add(...)
    > is that possible ?
    No - va_start needs to know the last named argument, so you always need at least one named parameter

    > i want it to
    > terminate after the last argument (it need not be zero)
    > how can it be done ?
    It can't - not in standard C anyway
    The loop which loops through the arguments needs to know how many times to loop - there is no magical compiler generated value which signifies the end of the list
    There are two basic ways to do this
    1. Encode the number of variable parameters - like printf does with all it's conversion formats
    2. Mark the end of the list with a sentinel value such as 0, like you have done

  7. #7
    Registered User moonwalker's Avatar
    Join Date
    Jul 2002
    Posts
    282

    hmm

    >Encode the number of variable parameters - like printf does with all it's conversion formats

    could you elaborate this one please?
    Last edited by moonwalker; 08-04-2002 at 06:37 AM.

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    printf( "%d %d", 1, 2 );
    The number of % tell you the number of additional parameters.

    In your case, you could just do this to provide the count directly
    Code:
    #include <stdio.h>
    #include <stdarg.h>
    
    void add ( char *say, int num, ... ) {
        int answer = 0;
        int temparg = 0;
        int i;
        va_list argumentlist;
    
        va_start(argumentlist, num);
        for ( i = 0 ; i < num ; i++ ) {
            temparg = va_arg(argumentlist, int);
            answer = answer + temparg;
            printf("temparg is %d\n", temparg);
        }
        va_end(argumentlist);
        printf("%s %d\n", say, answer);
    }
    
    int main() {
        add("Addition result: ", 1, 1 );
        add("Addition result: ", 2, 1, 2 );
        add("Addition result: ", 3, 1, 2, 3 );
        return 0;
    }

  9. #9
    Just because ygfperson's Avatar
    Join Date
    Jan 2002
    Posts
    2,490
    i want it to terminate after the last argument (it need not be zero). how can it be done ?
    the stack has no boundaries, therefore, the function needs some help in determining what and where the variables are. normally, it would use the function prototype for fixed-length functions. but if it's a variable argument function, the number of arguments could theoretically go on forever. you need to somehow tell the program where it ends, and the way to do that is to give it some number-of-args info. printf stores it in the string, salem's example stores it in a fixed int parameter.

    you can also use that explanation to show why void add(...) won't work. the function void add(...) doesn't give any number of arguments info to itself, so it can't figure out how many (if any) variables to get from the stack.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. GradeInfo
    By kirksson in forum C Programming
    Replies: 23
    Last Post: 07-16-2008, 03:27 PM
  2. Question about printing a variable???
    By Hoser83 in forum C++ Programming
    Replies: 2
    Last Post: 03-31-2006, 01:57 PM
  3. Replies: 10
    Last Post: 09-27-2005, 12:49 PM
  4. How slow are variable arguments?
    By dwks in forum C Programming
    Replies: 5
    Last Post: 09-18-2005, 12:11 PM
  5. Variable number of arguments
    By dit6a9 in forum Windows Programming
    Replies: 3
    Last Post: 08-10-2004, 08:58 AM