Variable Arguement With Class Reference As 1st Parameter
I have the following code :
#include <cstdarg>
#include <iostream>
using namespace std;
class a {
};
void fun1(a& aa, ...)
{
va_list argp;
va_start(argp, aa);
char *p = 0;
while ((p = va_arg(argp, char *)) != 0) {
cout << p << endl;
}
va_end(argp);
}
void fun2(char *aa, ...)
{
va_list argp;
va_start(argp, aa);
char *p = 0;
while ((p = va_arg(argp, char *)) != 0开发者_如何学编程) {
cout << p << endl;
}
va_end(argp);
}
int main()
{
cout << "fun2" << endl;
fun2("a", "1", "2", (char *)0);
cout << "fun1" << endl;
fun1(a(), "1", "2", (char *)0);
getchar();
}
Everything works fine with fun2. However, fun1 will just crash.
May I know how can I prevent from crashing, at the same time able to use class reference as 1st parameter.
Currently, it prints :
fun2
1
2
fun1
then crash.
I wish
fun2
1
2
fun1
1
2
You can't use a reference parameter as the last named parameter with va_start. The reason is because va_start takes the address of the named parameter to find the location of the rest of the arguments. However, taking the address of a reference gives the address of the variable pointed at by the reference, not the address of the parameter itself. Your options are:
1) change the variable type from a reference to a pointer (or a non-reference if you are OK with a copy of the passed in variable).
2) Add an additional required parameter so that the reference isn't the last named parameter. The additional parameter can be a useful parameter, such as one of the char* you are going to pass to your particular function, or it can be a dummy variable you just ignore.
3) Change the definition of va_start. It's not recommended, but you can do it. See http://support.microsoft.com/kb/119394 for a non-portable redefinition.
It looks to me like you're crashing in fun2
.
Because you're calling va_arg
too many times and screwing up the stack.
You must only call va_arg
the same number of times as there are parameters.
Both fun1
and fun2
terminate the loop when they encounter a NULL
or 0
parameter. You are never passing one. Change main
to:
int main()
{
cout << "fun2" << endl;
fun2("a", "1", "2", NULL);
cout << "fun1" << endl;
fun1(a(), "1", "2", NULL);
getchar();
return 0;
}
Note I haven't compiled this, but it should work. You may have to follow janm's advice as well.
Update: I set down and thought about this again. You have to either:
- Instantiate an object of type
a
inside ofmain
and pass it or... - Following janm's advice and change
a& aa
infun2
toa const& aa
When I tried to compile the original under g++, I was greeted with the following error:
error: invalid initialization of non-const reference of type 'a&' from a temporary of type 'a'
error: in passing argument 1 of 'void fun1(a&, ...)'
Essentially, you cannot pass a temporary variable as a non-const
reference. See this SO question and this Herb Sutter GotW for some of the gory details.
I'm sorry to hear this code doesnt work. I notice if fun2(aa is a ptr instead of a ref the code works. I also notice while trying to compile on gcc (via http://codepad.org/) you pass "a" into fun2 which is a char*. codepad/gcc complained about it not being a const char*. In codepad this code works. In my copy of VS2008 it crashes and 2010b2 as well.
My recommendation is to avoid va params but i'll assume you can't so i suggest not to use ref and use pointers. Or switch to gcc but i wouldnt do that unless there are no other (reasonable) option.
#include<cstdlib>
#include <cstdio>
#include <ios>
#include <iostream>
using namespace std;
class a {
};
void fun1(a& aa, ...)
{
//cout<< "sizeof" << sizeof(aa) << "&aa == " << &aa;
va_list argp;
va_start(argp, aa);
char *p = 0;
while ((p = va_arg(argp, char *)) != 0) {
cout << p << endl;
}
va_end(argp);
}
void fun2(const char *aa, ...)
{
va_list argp;
va_start(argp, aa);
char *p = 0;
while ((p = va_arg(argp, char *)) != 0) {
cout << p << endl;
}
va_end(argp);
}
int main()
{
cout << "fun2" << endl;
fun2("a", "1", "2", 0);
cout << "fun1" << endl;
a aa;
//cout<< "sizeof" << sizeof(aa) << "&aa == " << &aa;
fun1(aa, "1", "2", 0);
getchar();
}
You are passing a non-const reference to a temporary. Change the fun1 prototype to:
void fun1(a const& aa, ...)
Update:
Haven't used varargs for a long time, missed that a terminating parameter wasn't being passed. See D. Shawley's answer; you must pass a terminating parameter if you're going to use that as your interface.
精彩评论