Reputation: 11252
Is there a standard C/C++ function that, given a printf
format string, returns the number of arguments it expects? E.g.:
num_printf_args("%d %s") == 2;
num_printf_args("%.1f%%") == 1;
num_printf_args("%*d") == 2;
Just counting the number of %
in the format string would be a first approximation, which works in the first example, but obviously not in the second and third ones.
I know gcc can do this, since at compile time it complains when the number of arguments (and also their type) actually passed to printf
does not match the format string.
Upvotes: 4
Views: 1812
Reputation: 36607
No standard function to do this.
However, it would be easy to implement.
Count the number of %
that are not followed by another %
. The add 1
for every one of those counted %
immediately followed by a *
.
When counting runs of %
characters, don't allow overlaps. So "%%%d" should result in a value of 1
(not 0
, and certainly not 2
or 3
).
EDIT - text below added following comment from user694733
This will suffice for format strings along the lines of the three examples you gave. However, as noted by user694733 in comments, this is not the whole story.
In general terms, a format specifier follows the prototype %[flags][width][.precision][length]specifier
. The approach above is a starting point, and will work for format strings have have no flags
, a possible *
in width
specifier, no *
in the precision
specifier, and overlooks length
and specifier
fields. All of those need to be considered, for a general format string, and the string parsed accordingly. The effort to do that depends on how robust you need your count to be - for example, more effort if you need to detect an invalid format string.
Upvotes: 6
Reputation: 3496
I'm not sure why you need this, however your problem might be solved in this way (accepted answer from this question: Variadic macro trick).
As suggested in comments, you can wrap the call of printf
into a macro that will first count the number of arguments required and then proceed to whatever you want to do.
Code from blog post:
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N
// to verify, run the preprocessor alone (g++ -E):
VA_NUM_ARGS(x,y,z)
Upvotes: 3