Question about Variable Arguments

Greetings all,

I have a question about variable arguments. I have found that I can easily make a variable argument function that invokes one of the system provided vFuncs(), such as vsnprintf() or vprintf(), etc.

For example:

[code]void genericReply(const char *prefix, const char *format, …) {
va_list args;

va_start(args, format);
printf(prefix);
vprintf(format, args);
va_end(args);

}[/code]

This works as I expect.

However, I find that if I try to chain two of my variable functions together, then it no longer works. For example, if I cated the following function that calls generiReply() then it won’t work:

[code]void Error(const char *format, …) {
va_list args;

va_start(args, format);
genericReply("Error: ", format, args);
va_end(args);

}[/code]

I know that this is a silly example, and there are probably a million ways to not do this. However, I am more interested in learning why doesn’t this work?

The references to variable arguments that I have are very terse. Usually a single page with a few paragraphs that gloss over the first example, but I find no mention about limitations, or how to chain like I want. Or why chaining won’t work.

Can anyone elightened me on this?

Thanks,

-=John

Just a quick look at this suggests to me that you are confused about what is going on. Let me try to explain in terms of the usual calling convention. ‘C’ programs push arguments into the stack in reverse order. So if you have a function f(a,b) the b variable gets pushed first and then a. So the variable at the bottom of the stack is always the first one. Now, look at your example. Your genericReply() function expects prefix to be at the bottom of the stack, format next, and then a variable number of other values above it. What does Error() send to genericReply()? It sends exactly three values, a pointer to the string “Error:”, a pointer to format, and a pointer to a list of pointers. Is it clear yet why this will not work?

Hmmm… I think I get it. When Error() passes arg to genericReply() its not pushing on all of the arguments, its pushing on the local pointer arg.

Obvious!

Now, is there a correct way to do what I want to do? I Initially I thought of the following

[code]void genericReply(const char *prefix,
const char *format,
va_list args) {
printf(prefix);
vprintf(format, args);
}

void Error (const char *format, …) {
va_list args;

va_start(args, format);
genericReply("Error :", format, args);
va_end(args);

}[/code]

But it didn’t work.

I did run the above through the preprocessor to see if that could help me decipher some more. I found:

[code]void Error (const char *format, …) {
va_list args;

__builtin_va_start(args,format);
genericReply("Error :", format, args);
__builtin_va_end(args);

}[/code]

But __builtin_va_start() is a dead end for me right now. I’ll do some googling tomorrow, but if anyone knows of how to do this I would love to learn. Or if this is just a limitation… well… I’ll be disapointed, but won’t waste any more time on it.

Thanks again.

-=John

I would have expect the code you posted to work?

Blarg!

It DID work. I came home, logged onto another machine retyped the new solution by memory and it worked.

I logged back onto work machines, and revisited what I had there, and founda typo.

I had created a genericReply2() function in the large hacked up proof of concept file but when I copied it into the message here I retyped it but correctly this time.

/smack and I gripe at others for not doing straight cut and paste.

Sorry for wasting the time on this last one.

This alternative does work. But now I question… is it wise to do this? Or might I be setting myself up for some nastiness later.

Thanks for your patience,

-=John

Your code is clean, this is NOT a hack, that’s the way to do it.