Reputation: 42984
MSDN shows this sample code snippet for vsnprintf_s
:
// crt_vsnprintf_s.cpp #include <stdio.h> #include <wtypes.h> void FormatOutput(LPCSTR formatstring, ...) { int nSize = 0; char buff[10]; memset(buff, 0, sizeof(buff)); va_list args; va_start(args, formatstring); nSize = vsnprintf_s( buff, _countof(buff), _TRUNCATE, formatstring, args); printf("nSize: %d, buff: %s\n", nSize, buff); } int main() { FormatOutput("%s %s", "Hi", "there"); FormatOutput("%s %s", "Hi", "there!"); FormatOutput("%s %s", "Hi", "there!!"); }
In this sample, va_start
is called without a matching va_end
.
Is this a doc bug in MSDN, or should we just call va_start
before invoking vsnprintf_s
and then let this function do the cleanup (i.e. calling va_end
) for us?
BTW: I tried the above code and it works with VS2015 with Update 3, but I don't know if it's just undefined behavior...
Upvotes: 8
Views: 1524
Reputation: 30911
Assuming that vsnprintf_s
is supposed to be similar to vsnprintf
, then you shouldn't expect it to invoke va_end()
for you:
The functions
vprintf()
,vfprintf()
,vdprintf()
,vsprintf()
,vsnprintf()
are equivalent to the functionsprintf()
,fprintf()
,dprintf()
,sprintf()
,snprintf()
, respectively, except that they are called with ava_list
instead of a variable number of arguments. These functions do not call theva_end
macro. Because they invoke theva_arg
macro, the value ofap
is undefined after the call. Seestdarg(3)
.
(my emphasis)
Upvotes: 1
Reputation: 206697
va_end
needs to be called for every va_start
. From http://en.cppreference.com/w/c/variadic/va_end:
If there is no corresponding call to
va_start
orva_copy
, or ifva_end
is not called before a function that callsva_start
orva_copy
returns, the behavior is undefined.
Not only do you need va_end
but you also need to make sure that your function does not return before va_end
is executed if va_start
or va_copy
is executed.
To answer your question - yes, this is a documentation bug in MSDN.
Upvotes: 7
Reputation: 224387
From the MSDN page for va_arg
, va_copy
, va_end
, va_start
:
After all arguments have been retrieved,
va_end
resets the pointer to NULL.va_end
must be called on each argument list that's initialized withva_start
orva_copy
before the function returns.
So yes, this is a documentation bug.
Upvotes: 3