va_start problem

G

gyan

Why it is that following program behaving like this:

1 #include <stdlib.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4
5 void comd(char *p,int a, ...);
6 void f(void);
7
8 main(){
9 f();
10 }
11
12 void f(void) {
13 char *p = (char *)malloc(10);
14 comd(p,5,'p','a','d','h','j');
15
16 }
17 void comd(char *p,int a, ...)
18 {
19 int i;
20
21 char *q;
22
23 va_list ap;
24 va_start(ap,a);
25 q=p;
26 for(i=0;i<=a;i++)
27 {
28 *p++ = va_arg(ap,char);
29 }
30 printf("\n p = %s\n",q);
31 va_end(ap);
32 }
33
above program give output as
p = padhj
Now if i change line nos 14 to
comd(p,4,'p','a','d','h','j');
then also output is same?
how how va_start exactly locate startingg point
in ap?
 
K

Kenneth Brody

gyan said:
Why it is that following program behaving like this:

1 #include <stdlib.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4
5 void comd(char *p,int a, ...);
6 void f(void);
7
8 main(){
9 f();
10 }
11
12 void f(void) {
13 char *p = (char *)malloc(10);
14 comd(p,5,'p','a','d','h','j');
15
16 }
17 void comd(char *p,int a, ...)
18 {
19 int i;
20
21 char *q;
22
23 va_list ap;
24 va_start(ap,a);
25 q=p;
26 for(i=0;i<=a;i++)

In this case, you will go from 0 though 5, for a total of _6_ items.
That should be "i < a".
27 {
28 *p++ = va_arg(ap,char);
29 }
30 printf("\n p = %s\n",q);
31 va_end(ap);
32 }
33
above program give output as
p = padhj

Actually, the output included an extra character after the 'j', as
you ran off the end of your list. Apparently, whatever happened to
be there ended up being a non-printable character, and you didn't
see it.
Now if i change line nos 14 to
comd(p,4,'p','a','d','h','j');
then also output is same?
how how va_start exactly locate startingg point
in ap?

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
A

Anand

gyan said:
Why it is that following program behaving like this:

1 #include <stdlib.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4
5 void comd(char *p,int a, ...);
6 void f(void);
7
8 main(){
int main(void) { // Read FAQ to know why
return 0; // Read FAQ to know why
10 }
11
12 void f(void) {
13 char *p = (char *)malloc(10);
// need to include stdlib.h // Read FAQ to know why
char *p = malloc(10); // Read FAQ to know why
14 comd(p,5,'p','a','d','h','j');
15
16 }
17 void comd(char *p,int a, ...)
18 {
19 int i;
20
21 char *q;
22
23 va_list ap;
24 va_start(ap,a);
25 q=p;
26 for(i=0;i<=a;i++)
for(i=0;i<a;i++) // to add a number of elements..
// you were adding a+1
27 {
28 *p++ = va_arg(ap,char);
29 }
*p = '\0'; // null terminate the string
 
M

Martin Ambuhl

gyan said:
Why it is that following program behaving like this: [....]
> how how va_start exactly locate startingg point
> in ap?

That is not your problem.

No one knows why your program does as it does; you have no reason to
expect it to run at all.

This line might well cause your program to abort:
> 28 *p++ = va_arg(ap,char);
All the arguments are ints.

This line leads to trying to get more arguments than there are
> 26 for(i=0;i<=a;i++)

and your failure to terminate the string properly means that
> 30 printf("\n p = %s\n",q);
leads to pssibly disastrous outcomes.

Compare your code to the following, paying attention to the lines marked
with /* mha */:

#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>

void comd(char *p, int a, ...);
#define BIGENOUGH 1024

int /* mha */ main()
{
char p[BIGENOUGH];
comd(p, 5, 'p', 'a', 'd', 'h', 'j');
comd(p, 4, 'p', 'a', 'd', 'h', 'j');
return 0;
}
void comd(char *p, int a, ...)
{
int i;
char *q;
va_list ap;

printf("\n comd called with a = %d\n", a);
va_start(ap, a);
q = p;
for (i = 0; i < /* mha */ a; i++)
*p++ = va_arg(ap, int); /* mha */
*p = 0; /* mha */
printf("p = %s\n", q);
va_end(ap);
}


comd called with a = 5
p = padhj

comd called with a = 4
p = padh

[OP's code follows, with those obnoxious line numbers]
 
L

lawrence.jones

gyan said:
28 *p++ = va_arg(ap,char);

In addition to the problems others have noted, arguments to varargs
functions undergo the default argument promotions which means that char
and short get promoted to int and float gets promoted to double, which
means that line should be:

*p++ = va_arg(ap, int);

-Larry Jones

Everybody's a slave to routine. -- Calvin
 
C

Christian Bau

"gyan said:
Why it is that following program behaving like this:

1 #include <stdlib.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4
5 void comd(char *p,int a, ...);
6 void f(void);
7
8 main(){
9 f();
10 }
11
12 void f(void) {
13 char *p = (char *)malloc(10);
14 comd(p,5,'p','a','d','h','j');
15
16 }
17 void comd(char *p,int a, ...)
18 {
19 int i;
20
21 char *q;
22
23 va_list ap;
24 va_start(ap,a);
25 q=p;
26 for(i=0;i<=a;i++)
*****************

I think you meant
for (i = 0; i < a; i++)
27 {
28 *p++ = va_arg(ap,char);
29 }

At this point, you forgot to store a missing 0 character at the end of
the string.
 
M

Martin Ambuhl

In addition to the problems others have noted, arguments to varargs\
s/In addition to/Among the problems/
See my post an hour and a half before yours.
 
T

those who know me have no need of my name

in comp.lang.c i read:
See my post an hour and a half before yours.

ahh, someone repealed propagation effects from the usenet? about time!
 
P

Peter Nilsson

In addition to the problems others have noted, arguments to varargs
functions undergo the default argument promotions which means that char
and short get promoted to int and float gets promoted to double, which
means that line should be:

*p++ = va_arg(ap, int);

For a free-standing implementation, it may pay to be safer with...

#if UCHAR_MAX > INT_MAX
*p++ = va_arg(ap, unsigned);
#else
*p++ = va_arg(ap, int);
#endif
 
A

Anand

Martin said:
Anand said:
gyan said:
1 #include <stdlib.h>
[...]

// need to include stdlib.h // Read FAQ to know why


An interesting observation. Since he did include <stdlib.h>, what's
your point?
Oops.. I missed it (sorry gyan), probably (1%) due to small indentation
and mostly (99%) due to my negligence..
 
A

Anand

Martin said:
Anand said:
gyan said:
1 #include <stdlib.h>
[...]

// need to include stdlib.h // Read FAQ to know why


An interesting observation. Since he did include <stdlib.h>, what's
your point?
Oops.. I missed it.

I missed it due to small indentation change (1%) and
mostly due to my negligenc (99% .)

sorry gyan.
 
A

Anand

Martin said:
gyan wrote: [...]

This line might well cause your program to abort:
28 *p++ = va_arg(ap,char);
All the arguments are ints.
[...]
if the chars are always promoted to int in variadic function then why
there's va_arg(ap,char)?
I mean.. why would it be different from va_arg(ap,int)?
Did I miss something?
 
M

Martin Ambuhl

Anand said:
Martin said:
gyan wrote:
[...]

This line might well cause your program to abort:
28 *p++ = va_arg(ap,char);
All the arguments are ints.

[...]
if the chars are always promoted to int in variadic function then why
there's va_arg(ap,char)?

Who said that there _is_, in any meaningful sense, 'va_arg(ap,char)'?
va_arg is a macro, so you can make all sorts of nonsensical strings
involving it.
Any function not governed by a prototype (or as an argument in the '...'
part of a prototype) will have its argument expressions converted by the
usual argument conversions. Any argument with rank less than int will
be converted to int if the type is signed or if all the values of that
type can be represented as an int, otherwise to unsigned int. Types of
rank less than int include short, unsigned short, char, unsigned char,
signed char, and _Bool.

Note that C99 retains the float->double conversion here even though it
doesn't in the usual unitary conversions.
I mean.. why would it be different from va_arg(ap,int)?

unless sizeof(int) == sizeof(char), there is an obvious difference. The
other one is that 'va_arg(ap, char)' has no coherent meaning, since the
argument is never a char.
Did I miss something?

Or else added something.
 
A

Anand

Martin said:
Anand said:
Martin said:
gyan wrote:

[...]

This line might well cause your program to abort:
28 *p++ = va_arg(ap,char);
All the arguments are ints.


[...]
if the chars are always promoted to int in variadic function then why
there's va_arg(ap,char)?


Who said that there _is_, in any meaningful sense, 'va_arg(ap,char)'?
[...]
Bad wordings from my side :-(

I wanted to know the behavior/usage of va_arg(ap, char), if at all?
I got the answer now " *NO* meaningful usage."
Thanks for clarifying


I knew that integer promotions in variadic functions.. But somehow I
thought va_arg would handle this.
To add to my confusion my compiler handled the smaller-than-int properly
sunch that if I write va_arg(ap, char) it would work (by making
something like to va_arg(ap, int)).
 
O

Old Wolf

In addition to the problems others have noted, arguments to varargs
functions undergo the default argument promotions which means that
char and short get promoted to int and float gets promoted to double,
which means that line should be:

*p++ = va_arg(ap, int);

True, but the arguments were all ints in the first place, so no
promotion occurs in this particular example.
 
G

gyan

Hi all,
thanks for your replies.
I got, what was wrong with my program.
But, no body pointed out how va_start locate starting point of variable
argument list?
in my program, does it depends on value of a or *p.
Or it is like that va_arg will always fetch 'p' first time and then carry
on to 2nd argument and so on?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top