El código original falla porque intenta usar printf()
donde necesita usar vprintf()
. Tomando puntos dudosos como los logOpen
y logClose
declaraciones a su valor nominal (dada la notación, es de suponer que son macros que abren y cierran la corriente flog
archivo), el código debe ser:
void logPrintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
logOpen;
vfprintf(flog, fmt, ap);
logClose;
va_end(ap);
va_list ap2;
va_start(ap2, fmt);
vprintf(fmt, ap2);
va_end(ap2);
}
No hay requisito particular para usar dos variables separadas va_list
; está perfectamente bien usar el mismo dos veces siempre que use va_end()
antes de usar va_start()
nuevamente.
void logPrintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
logOpen;
vfprintf(flog, fmt, ap);
logClose;
va_end(ap);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
Cuando un valor va_list
se pasa a otra función (vfprintf()
y vprintf()
en este código), se debe asumir que ya no puedan utilizarse en la función actual es. Solo es seguro llamar al va_end()
en él.
No hay necesidad de va_copy()
en este código. Funciona, pero no es necesario. Es necesario va_copy()
en otras circunstancias, como cuando se pasa a la función de un va_list
y que necesita para procesar la lista dos veces:
void logVprintf(const char *fmt, va_list args1)
{
va_list args2;
va_copy(args2, args1);
logOpen;
vfprintf(flog, fmt, args1);
logClose;
vprintf(fmt, args2);
va_end(args2);
}
Tenga en cuenta que en este código, es responsabilidad del código de llamada para llamar va_end()
en args1
. En efecto, la norma dice:
cada invocación de la va_start
y va_copy
macros se corresponde con una invocación correspondiente de la va_end
macro en la misma función.
Dado que la función logVprintf()
no llama ya sea va_start
o va_copy
para inicializar args1
, no puede legítimamente llamar va_end
en args1
. Por otro lado, el estándar requiere que llame al va_end
para args2
.
La función logPrintf()
puede ser implementada en términos de logVprintf()
ahora:
void logPrintf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
logVprintf(fmt, args);
va_end(args);
}
Esta estructura - una función operativa que toma un va_list
y una función de cubierta que lleva puntos suspensivos (argumentos variables) y los pasa a la operativa función después de la conversión a va_list
- a menudo es una buena manera de trabajar. Tarde o temprano, generalmente encontrará una necesidad para la versión con un argumento va_list
.
Necesita usar vprintf por segunda vez, no printf. –