C Board  

Go Back   C Board > General Programming Boards > C Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 08-03-2002, 09:34 PM   #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.
------------------------------------------------------------------------
moonwalker is offline   Reply With Quote
Old 08-03-2002, 10:16 PM   #2
moi
Registered User
 
moi's Avatar
 
Join Date: Jul 2002
Posts: 945
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!
moi is offline   Reply With Quote
Old 08-03-2002, 10:41 PM   #3
Just because
 
ygfperson's Avatar
 
Join Date: Jan 2002
Posts: 2,502
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.

Quote:
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.
ygfperson is offline   Reply With Quote
Old 08-03-2002, 11:53 PM   #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.
moonwalker is offline   Reply With Quote
Old 08-04-2002, 06:11 AM   #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
moonwalker is offline   Reply With Quote
Old 08-04-2002, 06:20 AM   #6
and the hat of Jobseeking
 
Salem's Avatar
 
Join Date: Aug 2001
Location: The edge of the known universe
Posts: 21,710
> 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
Salem is offline   Reply With Quote
Old 08-04-2002, 06:33 AM   #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.
moonwalker is offline   Reply With Quote
Old 08-04-2002, 07:31 AM   #8
and the hat of Jobseeking
 
Salem's Avatar
 
Join Date: Aug 2001
Location: The edge of the known universe
Posts: 21,710
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;
}
Salem is offline   Reply With Quote
Old 08-04-2002, 09:08 AM   #9
Just because
 
ygfperson's Avatar
 
Join Date: Jan 2002
Posts: 2,502
Quote:
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.
ygfperson is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
GradeInfo kirksson C Programming 23 07-16-2008 03:27 PM
Question about printing a variable??? Hoser83 C++ Programming 2 03-31-2006 01:57 PM
return values from function with variable number of arguments evo_x C++ Programming 10 09-27-2005 12:49 PM
How slow are variable arguments? dwks C Programming 5 09-18-2005 12:11 PM
Variable number of arguments dit6a9 Windows Programming 3 08-10-2004 08:58 AM


All times are GMT -6. The time now is 05:39 PM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22