How to determine if va_list is empty

I read that some compilers support va_list with macros, and users could overload functions with other macros to count va_list .

With visual studio, is there a way to determine if va_list (aka count == 0) is empty? Basically I would like to know this condition:

extern void Foo(const char* psz, ...); void Test() { Foo("My String"); // No params were passed } 

My initial thought was to do something like this:

 va_list vaStart; va_list vaEnd; va_start(vaStart, psz); va_end(vaEnd); if (vaStart == vaEnd) ... 

The problem is that va_end only sets the parameter to null.

 #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define _crt_va_end(ap) ( ap = (va_list)0 ) 

I thought, perhaps, by including the terminator, but I would like it to be hidden from the caller, so that the existing code does not need to be changed.

+4
source share
3 answers

It is impossible to tell how many arguments are passed through ... , and what type they are. Variadic function parameters can only be used if you have another way (for example, a printf style format printf ) to tell the function what to expect; and even then there is no way to verify the arguments.

C ++ 11 provides safe template types. I do not know if your compiler supports or whether it will be suitable for your problem.

+5
source

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); . . . // do something, or something else, . // based on the number of args in the list . va_end(vl); 

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.

+2
source

I know that my answer is not an β€œorthodox” answer, however, due to the limitations of the va_list macro, I found the following solution to work. We can look at va_list as an array of characters and, even better, with zero completion, so you can try

 va_list argptr; if(strcmp(argptr,"")) { // not empty } else { // empty } 

I tried this and it worked for me. I used Visual Studio 2013 Ultimate. Project type - Win32 console application. There are no compilation errors.

-2
source

All Articles