Die einzige relevante Anforderung im C99-Standard lautet:
7.15.1 Zugriffsmakros für Variablengeradenliste
1 [...] Jeder Aufruf der Makros va_start
und va_copy
muss durch einen entsprechenden Aufruf des Makros va_end
in derselben Funktion abgestimmt werden.
Es gibt keine Anforderung für die Reihenfolge mehrerer va_end
-Aufrufe, die mit der von va_start
übereinstimmen muss, oder umgekehrt, so dass Implementierungen beide Reihenfolgen akzeptieren müssen.
Sie könnten sogar ein fürchterliches Durcheinander wie folgt verwenden
void f(int a, ...) {
va_list ap;
goto b;
a:
va_end(ap);
return;
b:
va_start(ap, a);
goto a;
}
Dies entspricht allen Anforderungen des Standards, daher müssen es Implementierungen akzeptieren. Infolgedessen sind nicht einmal Tricks erlaubt, bei denen va_end
etwas mit nicht übereinstimmenden Klammern erweitert.
In der Praxis bin ich nicht einmal davon bewusst, dass irgendeine aktuelle Implementierung hat, bei der va_end
überhaupt notwendigen Effekt hat. Alle Implementierungen, die ich finden konnte, setzen höchstens den Wert (oder den ersten Teilwert, abhängig vom Typ) auf null, was dazu führen würde, dass eine weitere Verwendung von va_arg
fehlschlägt, aber keine Probleme verursachen würde, wenn Sie va_end
aus Ihrem Code weglassen. Die meisten tun nicht einmal das. Jetzt würde ich es tatsächlich nicht aus dem Code entfernen, da es legitime Gründe gibt, warum eine Implementierung (aktuell oder zukünftig) tatsächlich etwas in ihrem va_end
tun könnte, aber Sie können davon ausgehen, dass aktuelle und zukünftige Implementierungen zumindest versuchen werden, es so zu implementieren, dass es den Anforderungen des Standards entspricht.
Die historischen Implementierungen, die #define va_end(ap) }
verwenden, gehören der Geschichte an. Sie haben dieses Makro nicht in bereitgestellt und hatten nicht einmal einen -Header. Sie sollten sich keine Sorgen darüber machen.