Oryginalny kod kończy się niepowodzeniem, ponieważ próbuje użyć printf()
, gdzie musi użyć vprintf()
. Biorąc wątpliwych punktów jak logOpen
i logClose
sprawozdaniu w wartości nominalnej (biorąc pod uwagę zapis, przypuszczalnie są makra, które otwierają i zamykają strumień flog
pliku), kod powinien być:
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);
}
Nie ma szczególności wymóg stosowania dwie oddzielne zmienne va_list
; jest całkowicie OK, aby użyć tego samego dwa razy , o ile użyjesz va_end()
, zanim ponownie użyjesz va_start()
.
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);
}
Gdy wartość va_list
jest przekazywane do innej funkcji (vfprintf()
i vprintf()
w tym kodzie), należy założyć, że nie jest już wykorzystywane w bieżącej funkcji jest. Bezpiecznie jest wywoływać na nim tylko va_end()
.
W tym kodzie nie ma potrzeby stosowania va_copy()
. Działa, ale nie jest potrzebna. Musisz va_copy()
w innych okolicznościach, takich jak wtedy, gdy funkcja jest podjęło va_list
i trzeba przetworzyć listę dwukrotnie:
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);
}
pamiętać, że w tym kodzie, to odpowiedzialność kodu wywołującego zadzwonić va_end()
na args1
. Rzeczywiście, średnia mówi:
Każdy wezwaniem va_start
i va_copy
makr powinna być dopasowana przez odpowiedni wezwaniem va_end
makra w tej samej funkcji.
Ponieważ funkcja logVprintf()
nie wymaga ani va_start
lub va_copy
zainicjować args1
, nie można zasadnie nazwać va_end
na args1
. Z drugiej strony standard wymaga, aby wywołać va_end
dla args2
.
Funkcja logPrintf()
mogą być realizowane w warunkach logVprintf()
się:
void logPrintf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
logVprintf(fmt, args);
va_end(args);
}
Ta struktura - funkcja operacyjna, która przyjmuje va_list
i funkcję pokrywy, które ma symbol (zmienne argumentów) i przekazuje je do eksploatacji funkcja po konwersji na va_list
- często jest dobrym sposobem na pracę. Prędzej czy później zazwyczaj potrzebujesz wersji z argumentem va_list
.
Musisz użyć vprintf po raz drugi, a nie printf. –