As a part of my program I use:
int ret = vprintf (format, args);
The args I get on the stack and I can’t know what actually was pushed on the stack.
The format is a string, which I can read.
The above approach works until I have to print floats. When I print float I get some strange numbers …
I checked that if I call float fArg = *(reinterpret_cast<const float*>(args) – and then print fArg the correct value is printed (I tried it when args was consisted only from one actual argument)
So probably I need special behavior for "%...f" sub-format – the corresponding (sub)argument should be cast
to float. (The ... notation means that precision, width etc. could be added before f)
How can I implement it?
Note that with variable-length argument lists, all
floatvalues are promoted to (and passed as)doublevalues. You cannot reliably use:because the language never places a float value on the stack. You would have to write:
This may be your entire problem.
If not, it is likely that you will need to scan the format string, and isolate the format specifiers, and implement a significant portion of the core
printf()code. For each specifier, you can collect the appropriate value from theargs. You then simply call the appropriateprintf()function on a copy of the initial segment of the format string (because you can’t modify the original) with the correct value. For your special case, you do whatever it is you need to do differently.It would be nice to be able to pass the
argsparameter tovprintf()so it deals with collecting the type, etc, but I don’t think that’s portable (which is undoubtedly a nuisance). After you’ve passed ava_listvalue such asargsto a function that usesva_arg()on it, you cannot reliably do anything other thanva_end()on the value after the function returns.Earlier this year, I wrote an
printf()-style format string analyzer for POSIX-enhanced format strings (which support then$notation to specify which argument specifies a particular value). The header I created contains (along with enumerations forPFP_Errno,PFP_Status,FWP_NoneandFWP_Star):The parse function analyzes the source and sets the appropriate information in the structure. The create function takes a structure and creates the corresponding format string. Note that the conversion specifier in the example (
%3$+-*2$.*1$llX) is valid (but a little dubious); it converts anunsigned long longinteger passed as argument number 3 with a width specified by argument 2 and a precision specified by argument 1. You probably could have a longer format, but only by a couple of characters without repetition, even if you used tens or hundreds of arguments in total.