Reputation: 170489
First, there's no portable way to compute the length of va_list
. Perhaps there's a way to do this in debug (not optimized) configuration of Visual C++?
Specifically I have a variadic function:
void MyVariadic( const char* format, ... )
{
}
(and I cannot change the signature) and I want to detect cases where format
contains percentage characters and the arguments list is empty (which likely means that someone passed a whatever string directly in place of format
instead of using %s
) and once I detect such cases I can assert()
or something.
Is there a way to do this in debug non-optimized build in Visual C++?
Upvotes: 3
Views: 254
Reputation: 217293
One possible way is to use variadic macro (with hardcoded limit):
#define COUNT_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define COUNT(...) COUNT_N(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
// Warning: COUNT() return 1 (as COUNT(A)) :-/
#define ARG1(S, ...) S
And then do something like:
#define MyVariadic_And_Check(...) do { \
Check(ARG1(__VA_ARGS__), COUNT(__VA_ARGS__) - 1); \
MyVariadic(__VA_ARGS__); } while(false)
With Check(const char* format, int count)
a function to check parameter count.
Note: Since MyVariadic has at least const char* format
, COUNT
will give correct answer.
In C++11, you may use something like:
template <typename ... Args>
void MyVariadic_And_Check(const char* format, Args&&...args);
to verify both count and type.
Upvotes: 0
Reputation: 179877
(From comments)
The problem is basically in calls like MyVariadic(str)
where str
is a const char[]
known only at runtime. We can't change the signature of void MyVariadic(const char*, ...)
but we can add an overload. void MyVariadic(const char*)
is a better match.
From void MyVariadic(const char* str)
it's hard to forward to void MyVariadic(const char*, ...)
. The generic solution is to cast &MyVariadic
to void (*p)(const char*, ...)
but in this particular case const char*
is a printf-like format. That means we can forward to MyVariadic("%s", str)
.
Upvotes: 2
Reputation: 7202
Since you are okay with Visual C++-specific solutions and if your goal is to help detect mismatched printf-style format strings, consider using SAL Annotations. A build that you run with code analysis turned on will report errors if the format string and the arguments don't match up.
The annotation you want is _Printf_format_string_
. Take a look at how printf
is annotated in stdio.h
for inspiration.
Consider the following code:
int i = 12;
printf("%d %s", i);
Visual C++ 2013 run with code analysis reports for me
C6063 Missing string argument to 'printf' that corresponds to specifier '2'.
Upvotes: 4