The following program works on a 64-bit Linux machine, but crashes on a 32-bit Linux machine.
#include <cstdarg>
#include <iostream>
void proc_int(std::va_list va)
{
std::cout << va_arg(va, int);
}
void proc_str(std::va_list va)
{
std::cout << va_arg(va, const char*);
}
void outputv(std::va_list va)
{
proc_int(va);
std::cout << " ";
proc_str(va);
std::cout << "\n";
}
void output(int dummy, ...)
{
va_list va;
va_start(va, dummy);
outputv(va);
va_end(va);
}
int main()
{
output(0, 42, "hello");
}
va_list
char*
struct __va_list_tag[1]
outputv
From cppreference,
If a
va_list
instance is created, passed to another function, and used viava_arg
in that function, then any subsequent use in the calling function should be preceded by a call tova_end
It's not wholly clear whether that (subsequent use) includes passing to another function, but it's certainly plausible.
Checking local (Linux) man page for comparison:
If
ap
[the va_list] is passed to a function that usesva_arg(ap,type)
then the value of ap is undefined after the return of that function
So you're simply not allowed to pass the va_list
around and use it the way you are, and the 32-bit version just happens to get away with it.
What changes can I make to make this program portable, preferably without changing the signature of outputv?
Well, just don't pass the va_list
into other functions and expect it to still work afterwards:
void outputv(std::va_list va)
{
std::cout << va_arg(va, int);
std::cout << " ";
std::cout << va_arg(va, const char *);
std::cout << "\n";
}