-
va_list confusion
Hey there, hope you're having an awesome weekend! :)
So............... yeah, my brain hurts. :D
I have two functions that work with va_lists: one ("Say") that uses vsnprintf. It works in isolation. There other ("Write") calls Say and also the ncurses function "vw_printw" 9like a printf except that it also takes a va_list and works in the "ncurses" library). The ncurses part, obviously, also works in isolation. But when I try to put them both in the same function, "weird happens." For some reason, instead of putting the data (a const char * in my tests) into the string, it inserts the text "^P". I'm guessing the problem is the fact that I don't really know how va_lists work under the hood. There's probably some pointer moving somewhere, or something that got NULLed somehow... lol idk...
Anyway, here's the code:
Code:
void Say(bool rightNow, const char *format, ...) {
/* Declare variables */
va_list args;
char buffer[256];
/* Pass the variable arguments into our buffer */
va_start(args, format);
vsnprintf(buffer, 256, format, args);
printw("Saying: \"%s\n\"", buffer);
va_end (args);
/* Stop speech if theuser wants this text spoken immediately */
if (rightNow) espeak_Cancel();
/* Tell eSpeak to speak our buffer */
espeak_Synth((const char *)buffer, strlen(buffer) + 1, 0, POS_SENTENCE, 0, espeakCHARS_AUTO, NULL, NULL);
}
void Write(bool speakImmediately, const char * format, ...) {
va_list list1, list2;
va_start(list1, format);
vw_printw(stdscr, format, list1);
va_end(list1);
// Tried a second va_list... no dice
va_start(list2, format);
Say(speakImmediately, (char *)format, list2);
va_end(list2);
}
// Then the code that calls it, "Say" by itself seems to work.
Say(false, (char *)"What the %s?", "puck");
// Obviously, printw by itself works as well.
// But with this, I get "What the ^P?"
Write(false, "What the %s?", "puck");
At this point I'm considering abandoning my write function completely and just always calling speak and printw, which is kind of a setback (I'll have to add a lot more variables so I can pass them in to both functions etc.) but I can't find anything on the interwebz that would provide a logical explanation. Maybe passing a va_list to a function that uses a va_list is invalid somehow? Anyway I'm compiling this with GCC on 64-bit Linux Mint, using -Wall, and I'm not getting any warnings.
Thanks in advance. :)
-
Code:
void Say2(bool rightNow, const char *format, va_list args) {
char buffer[256];
vsnprintf(buffer, 256, format, args);
printw("Saying: \"%s\n\"", buffer);
if (rightNow) espeak_Cancel();
espeak_Synth((const char *)buffer, strlen(buffer) + 1, 0,
POS_SENTENCE, 0, espeakCHARS_AUTO, NULL, NULL);
}
void Say(bool rightNow, const char *format, ...) {
va_list args;
va_start(args, format);
Say2(rightNow, format, args);
va_end(args);
}
void Write(bool speakImmediately, const char *format, ...) {
va_list list1, list2;
va_start(list1, format);
vw_printw(stdscr, format, list1);
va_end(list1);
va_start(list2, format);
Say2(speakImmediately, format, list2);
va_end(list2);
}
-
Hahahahahaha wow, so simple, and yet so genius! Thank you so much! :D Man, why didn't I think of that? :D
So I get how this works - it's pretty obvious - but what I don't understand is why it was necessary. I'd be interested in any info you may have on the subject, but it's just out of curiosity now - I got some more hacking to do on this project now that I'm past this stupid bug! :)
-
The basic problem you had was that you can't pass ... directly onto another function that also uses ...
You have to use a va_list as john.c showed.
> Anyway I'm compiling this with GCC on 64-bit Linux Mint, using -Wall, and I'm not getting any warnings.
Yeah, ... does that.
Parameters that match against ... get no type checking, no automatic promotion (or demotion) or anything.
-
I was under the impression that you could use _VA_ARGS__ in this case
But
It seem it can only be used in macros.
-
If I understand your question you are asking why you can't pass a va_list to a ... and have it "unpack" into separate variables again like the ones that were used to call the current function. All I can say is it simply doesn't work like that. It would be impossible for it to automatically unpack into separate variables correctly since it's up to you to tell it the types with va_arg. It's a very low-level and error-prone mechanism that exists primarily to implement the printf and scanf family of functions.