sharptooth
sharptooth

Reputation: 170489

Is there any way to know the number of variadic function arguments specific to Visual C++?

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

Answers (3)

Jarod42
Jarod42

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

MSalters
MSalters

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

chwarr
chwarr

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

Related Questions