I understand that this question is quite old, but I thought it might be useful to partially use it. Since Mike Seymour answered quite correctly, there is no absolutely reliable way to determine the number of arguments in va_list . Therefore, the traditional way of determining a variational function is to include a parameter that has this information: void func(const char *str, int count, ...); that defines the contract your callers should follow.
EDIT: Standard (7.16.1.1.3) is actually inactive for the value returned by va_arg(vl, type) for any call that passes after the end of the list of variable arguments. The most common case for most types is type-zero. However, CAVEAT EMPTOR is not necessary.
The value returned from va_arg(vl, type) when there are no more arguments is a value of type zero. For numeric types, this is 0. For pointers, this is a NULL pointer. For structs, this is a structure with all fields reset to zero. If you decide to copy va_list and try to count the copy, like this:
void func(const char *str, ...) { va_list vl; va_list vc; int x; int count; count = 0; va_start(vl, str); va_copy(vc, vl); do { x = va_arg(vc, int); if (x == 0) break; count++; } while (1) va_end(vc); . . .
You would need to make an assumption that the caller will abide by the contract so as not to miss NULL or a null value in the list. In any case, you must understand that the caller of the variational function is responsible for compliance with the specified contract. So write your function, publish the contract and sleep easy.
source share