I wrote a function that accepts a va_list
, and that is meant to be invoked iteratively by its caller. It should modify the va_list
and changes should persist back in the caller so that the next call to the function will proceed with the next argument.
I can't post that code specifically, but here's a snippet that reproduces the situation (godbolt link):
#include <stdarg.h>
#include <stdio.h>
void print_integer(va_list ap) {
printf("%i\n", va_arg(ap, int));
}
void vprint_integers(int count, va_list ap) {
for (int i = 0; i < count; ++i) {
print_integer(ap);
}
}
void print_integers(int count, ...) {
va_list ap;
va_start(ap, count);
vprint_integers(count, ap);
va_end(ap);
}
int main() {
print_integers(3, 1, 2, 3);
}
This works (prints "1 2 3") on my x86 platform because va_list
is passed by "reference" (it's probably declared as an array of one element, so va_list
arguments decay to a pointer). However, it does not work on my ARM platform (prints "1 1 1"), where va_list
seems to be defined as a pointer to something. On that platform, va_arg
always returns the first argument.
The next best option seems to be to make ap
a pointer:
#include <stdarg.h>
#include <stdio.h>
void print_integer(va_list *ap) {
printf("%i\n", va_arg(*ap, int));
}
void vprint_integers(int count, va_list ap) {
for (int i = 0; i < count; ++i) {
print_integer(&ap);
}
}
void print_integers(int count, ...) {
va_list ap;
va_start(ap, count);
vprint_integers(count, ap);
va_end(ap);
}
int main() {
print_integers(3, 1, 2, 3);
}
This works on ARM (with va_arg(*ap, ...)
), but it does not compile on x86. When I try print_integer(&ap)
on x86, Clang says:
error: incompatible pointer types passing '
struct __va_list_tag **
' to parameter of type 'va_list *
' (aka '__builtin_va_list *
')
This only seems to happen when taking the address of a va_list
passed as an argument, not when it's taken from a local variable. Unfortunately, I do need my v
variant to take a va_list
object and not a pointer to it.
It's easy to get consistent cross-platform value semantics for va_list
using va_copy
. Is there a cross-platform way to get consistent reference semantics for va_list
?