stdarg problems

O

Obnoxious User

Hi,

Can someone tell me what is wrong with the below program?
-------------------------------------------
int main()
{
f1( 25 > 50,"testing stdarg. ", "it is working", "if it is
working." );
return 0;
}

void f1(bool condition, const char * msg,...)
{
va_list ap;
va_start(ap, msg);

while (msg != 0 )
{
cout<< msg<<endl;
msg = va_arg(ap, const char *);
}
va_end(ap);

}
--------------------------------------------

the ouput is
------------------------------------------
testing stdarg.
it is working
if it is working.

UH??AWAVAUATSH??8H?E?

Cleaned up and compilable version of your code.

#include <cstdarg>
#include <iostream>

void f1(bool condition, const char * msg,...)
{
va_list ap;
va_start(ap, msg);
while (msg != 0 )
{
std::cout<< msg<<std::endl;
msg = va_arg(ap, const char *);
}
va_end(ap);
}

int main()
{
f1( 25 > 50,"testing stdarg. ", "it is working", "if it is working.",0 );
return 0;
}
 
N

nariknahom

Hi,

Can someone tell me what is wrong with the below program?
-------------------------------------------
int main()
{
f1( 25 > 50,"testing stdarg. ", "it is working", "if it is
working." );
return 0;
}

void f1(bool condition, const char * msg,...)
{
va_list ap;
va_start(ap, msg);

while (msg != 0 )
{
cout<< msg<<endl;
msg = va_arg(ap, const char *);
}
va_end(ap);

}
--------------------------------------------

the ouput is
------------------------------------------
testing stdarg.
it is working
if it is working.

UH??AWAVAUATSH??8H?E?
 
R

Robert Bauck Hamar

Obnoxious said:
Cleaned up and compilable version of your code.

#include <cstdarg>
#include <iostream>

void f1(bool condition, const char * msg,...)
{
va_list ap;
va_start(ap, msg);
while (msg != 0 )
{
std::cout<< msg<<std::endl;
msg = va_arg(ap, const char *);
}
va_end(ap);
}

int main()
{
f1( 25 > 50,"testing stdarg. ", "it is working", "if it is working.",0 );

I believe this should be

f1( 25 > 50,"testing stdarg. ", "it is working", "if it is working.",
static_cast<const char*>(0) );

To make it guaranteed to work. Variable argument functions are mine fields.

The reason is that you must use the same type in va_arg as in the call, and
also because the integer 0 is not required to have the same binary
representation as a null pointer.
 
R

Rolf Magnus

Hi,

Can someone tell me what is wrong with the below program?
This:

while (msg != 0 )

checks for a null argument, but with:
f1( 25 > 50,"testing stdarg. ", "it is working", "if it is
working." );

you never supplied one, so your function can't find the end of your argument
list.
 
A

aradhika_c

Hi,

Can someone tell me what is wrong with the below program?
-------------------------------------------
int main()
{
f1( 25 > 50,"testing stdarg. ", "it is working", "if it is
working." );
return 0;

}

void f1(bool condition, constchar* msg,...)
{
va_list ap;
va_start(ap, msg);

while (msg != 0 )
{
cout<< msg<<endl;
msg =va_arg(ap, constchar*);
}
va_end(ap);

}

--------------------------------------------

the ouput is
------------------------------------------
testing stdarg.
it is working
if it is working.

UH??AWAVAUATSH??8H?E?


Why don't you try msg != NULL and put , NULL as 4th unnamed argumnent
in the function call in the main function?
 
J

James Kanze

I believe this should be
f1( 25 > 50,"testing stdarg. ", "it is working", "if it is working.",
static_cast<const char*>(0) );
To make it guaranteed to work. Variable argument functions are
mine fields.

And C++ offers enough other possibilities that they typically
aren't needed.
The reason is that you must use the same type in va_arg as in
the call, and also because the integer 0 is not required to
have the same binary representation as a null pointer.

In practice, I don't know of a single 64 bit machine where they
have the same representation. The integer 0 is almost always a
32 bit quantity on 64 bit machines, where as a char const* is a
64 bit quantity. Depending on how arguments are passed, you may
end up with a very strange looking pointer if you just pass a 0,
without the cast.
 
N

nariknahom

So you have to always provide a NULL as the last argument. I thought
the compiler took care of it.
Shouldnt the compiler already know that?
 
R

Ron Natalie

Why don't you try msg != NULL and put , NULL as 4th unnamed argumnent
in the function call in the main function?
As others pointed out, NULL is an integral constant expression. There's
no guarantee that it can be retrieved by va_arg as a pointer.

He needs to use a null pointer value of type const char*.
 
R

Ron Natalie

So you have to always provide a NULL as the last argument. I thought
the compiler took care of it.

No, the compiler has no clue what you want to do. stdarg is pretty
lame and owes it's history to some very early C implementations of
printf.
Shouldnt the compiler already know that?

Known what?

While in C++ the fact that the function is declared with ... in the
parameter list means that it should be able to pass information like
the actual types and the number of args, historical compatibility with
loosy-goosy typed C functions precludes this.
 
N

nariknahom

Is the ellipsis( ... ) a part of C/C++ or stdarg.h? If its part of the
C/C++, then shouldnt the compiler know where the end of the arguments
is and automatically insert a NULL? Maybe this is not how C/C++ is
designed but what are the disadvantages if it is so?
 
R

Robert Bauck Hamar

Is the ellipsis( ... ) a part of C/C++

Yes. When C++ was designed, C generally used the syntax

int foo();

to declare functions. C had no type checking of the arguments, so this
means «declare function foo to take any number of arguments, and return an
int». In really old text books, code would often just declare functions
from the standard library instead of including the proper header. Foo could
be defined in another compilation unit as:

int foo(bar)
int bar;
{ return do_stuff(bar); }

As you can see, «any number of arguments» usually means «whatever the
function expects». Dennis Ritchie has commented on this here:
http://www.lysator.liu.se/c/chistory.ps.

For another comment on the implications, I refer to the third commandment:
http://www.lysator.liu.se/c/ten-commandments.html

In C++, the function declaration syntax came to use the syntax we know
today, but to support the concept «any number of arguments», as some C
library functions use, ... was introduced.
or stdarg.h?
No.

If its part of the C/C++, then shouldnt the compiler know where the end of
the arguments is
Yes.

and automatically insert a NULL?
No.

Maybe this is not how C/C++ is designed but what are the disadvantages if
it is so?

First of all, what is NULL? In C++, it's an integral constant, while in C,
it's an implemention defined pointer constant. There's no general way for
the compiler to know what types a function expects for ..., and it would be
nice if you could use more than one type in ...? So, while there are no
general disadvantages, there are no real advantages either. And if you can,
you should avoid using ... in functions.
 
R

Rolf Magnus

Is the ellipsis( ... ) a part of C/C++ or stdarg.h?

The ellipsis is part of both C and C++. stdarg.h is too. It provides the
facilities for using variable argument lists.
If its part of the C/C++, then shouldnt the compiler know where the end of
the arguments is and automatically insert a NULL?

What if I want some other way to determine the end, e.g. if NULL pointers
can be anywhere within the argument list? What if I want to pass integers
as arguments and not pointers? Which value should be inserted for the final
argument? How would the compiler know if my function expects an integer or
a pointer?
 
J

James Kanze

Is the ellipsis( ... ) a part of C/C++ or stdarg.h? If its part of the
C/C++, then shouldnt the compiler know where the end of the arguments
is and automatically insert a NULL?

Why? How? The C++ compiler has no idea as to what conventions
are being used to determine the number and type of the
arguments. As Ron pointed out, support for variable args was
really first designed to handle printf and company. No "NULL"
is needed, and since the argument types can vary, what type
should it be if the compiler generated it.

The ellipsis is present in C++ for historical reasons. When
dealing with a legacy interface, like printf or execl, conform
to what that interface requires. And don't use it in new code;
there are always better solutions.
Maybe this is not how C/C++ is
designed but what are the disadvantages if it is so?

Except for the fact that its unimplementable and doesn't make
sense, nothing.
 
J

James Kanze

First of all, what is NULL? In C++, it's an integral constant,
while in C, it's an implemention defined pointer constant.

In both languages, it's a "null pointer constant". In both
languages, the "usual" (and traditional) definition is simply
"0". In both languages, however, any integral constant
expression will do the trick. C also allows such expressions
cast to void*, but except under MS-DOS, it's rather exceptional.
 

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

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,062
Latest member
OrderKetozenseACV

Latest Threads

Top