vfprintf writes formatted output to a stream from a va_list. It lets a variadic wrapper delegate formatting instead of manually retrieving and classifying each argument. section 16.5.2
Forwarding a debug argument list
int printf_debug(const char *format, ...) { int ret = 0; if (iodebug) { va_list va; va_start(va, format); ret = vfprintf(iodebug, format, va); va_end(va); } return ret; } The wrapper initializes va with va_start, passes it and the format string to vfprintf, then finishes with va_end. The stream is selected separately from the formatting logic. section 16.5.2
Use the surrounding variadic interface carefully:
- Include stdarg.h and manage va_list with va_start and va_end. section 16.5.2
- Keep the format string and supplied arguments consistent; vfprintf removes the need for manual case analysis, but not the need for a valid argument convention. section 16.5.2
- Prefer a non-variadic interface for new designs when an equivalent fixed interface is practical. section 16.5.2
20 FILE* iodebug = 0;
21
22 /**
23 ** @brief Prints to the debug stream @c iodebug
24 **/
25 #ifdef __GNUC__
26 __attribute__((format(printf, 1, 2)))
27 #endif
28 int printf_debug(const char *format, ...) {
29 int ret = 0;
30 if (iodebug) {
31 va_list va;
32 va_start(va, format);
33 ret = vfprintf(iodebug, format, va);
34 va_end(va);
35 }
36 return ret;
37 }
!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":0},{\"line\":0,\"ch\":2}],[{\"line\":0,\"ch\":5},{\"line\":0,\"ch\":9}],[{\"line\":1,\"ch\":0},{\"line\":1,\"ch\":2}],[{\"line\":2,\"ch\":0},{\"line\":2,\"ch\":2}],[{\"line\":3,\"ch\":0},{\"line\":3,\"ch\":2}],[{\"line\":4,\"ch\":0},{\"line\":4,\"ch\":2}],[{\"line\":5,\"ch\":0},{\"line\":5,\"ch\":2}],[{\"line\":5,\"ch\":5},{\"line\":5,\"ch\":11}],[{\"line\":6,\"ch\":0},{\"line\":6,\"ch\":2}],[{\"line\":6,\"ch\":27},{\"line\":6,\"ch\":33}],[{\"line\":8,\"ch\":9},{\"line\":8,\"ch\":15}],[{\"line\":13,\"ch\":17},{\"line\":13,\"ch\":23}],[{\"line\":7,\"ch\":0},{\"line\":7,\"ch\":2}],[{\"line\":7,\"ch\":5},{\"line\":7,\"ch\":11}],[{\"line\":8,\"ch\":0},{\"line\":8,\"ch\":2}],[{\"line\":3,\"ch\":18},{\"line\":3,\"ch\":21}],[{\"line\":6,\"ch\":29},{\"line\":6,\"ch\":32}],[{\"line\":8,\"ch\":5},{\"line\":8,\"ch\":8}],[{\"line\":9,\"ch\":7},{\"line\":9,\"ch\":10}],[{\"line\":13,\"ch\":19},{\"line\":13,\"ch\":22}],[{\"line\":8,\"ch\":22},{\"line\":8,\"ch\":32}],[{\"line\":9,\"ch\":0},{\"line\":9,\"ch\":2}],[{\"line\":3,\"ch\":18},{\"line\":3,\"ch\":21}],[{\"line\":6,\"ch\":29},{\"line\":6,\"ch\":32}],[{\"line\":8,\"ch\":5},{\"line\":8,\"ch\":8}],[{\"line\":9,\"ch\":7},{\"line\":9,\"ch\":10}],[{\"line\":13,\"ch\":19},{\"line\":13,\"ch\":22}],[{\"line\":10,\"ch\":0},{\"line\":10,\"ch\":2}],[{\"line\":5,\"ch\":6},{\"line\":5,\"ch\":8}],[{\"line\":7,\"ch\":9},{\"line\":7,\"ch\":11}],[{\"line\":10,\"ch\":7},{\"line\":10,\"ch\":9}],[{\"line\":11,\"ch\":0},{\"line\":11,\"ch\":2}],[{\"line\":11,\"ch\":9},{\"line\":11,\"ch\":16}],[{\"line\":12,\"ch\":0},{\"line\":12,\"ch\":2}],[{\"line\":12,\"ch\":9},{\"line\":12,\"ch\":17}],[{\"line\":13,\"ch\":0},{\"line\":13,\"ch\":2}],[{\"line\":13,\"ch\":15},{\"line\":13,\"ch\":23}],[{\"line\":14,\"ch\":0},{\"line\":14,\"ch\":2}],[{\"line\":14,\"ch\":9},{\"line\":14,\"ch\":15}],[{\"line\":15,\"ch\":0},{\"line\":15,\"ch\":2}],[{\"line\":16,\"ch\":0},{\"line\":16,\"ch\":2}],[{\"line\":16,\"ch\":7},{\"line\":16,\"ch\":13}],[{\"line\":17,\"ch\":0},{\"line\":17,\"ch\":2}]]"}
!@%STYLE%@!
Inspect the complete printf_debug wrapper, including stream checking, va_list setup, vfprintf forwarding, and cleanup. section 16.5.2

