Advanced Java Services | varargs |
Die im Header <stdarg.h> bereitgestellten Macros ermöglichen es mit wenig Aufwand Funktionen mit beliebig vielen Parametern zu schreiben. Bekannte Funktionen wie int printf(const char* format, ...); oder int scanf ( const char * format, ... ); verwenden variable Argumentenlisten. Die drei Punkte nach dem Komma, auch Ellipse genannt, leiten die variable Argumentenliste ein. Bei beiden Funktionen fällt auf, daß die variable Liste am Ende der festen Argumentenliste steht. Das ist kein Zufall, sondern muß so sein. ISO C verlangt zusätzlich ein Argument mit einem Namen vor der Ellipse. Das Argument vor der Ellipse hat die Aufgabe, der Funktion die Länge der variablen Liste mitzuteilen, damit die übergebenen Parameterwerte lorrekt auf den Stack der Funktion ghelegt werden können. Bei printf etwa entspricht die Länge der Liste der Anzahl der Prozentzeichen im Formatstring. Ein Beispiel verdeutlicht das prinzipielle Vorgehen.
Der Header <stdarg.h> stellt eine Reihe von Makros bereit, die praktisch wie Pointer bzw. Funktionen verwendet werden können.
Makro | Bedeutung |
---|---|
va_list | Typmakro hinter dem ein Voidpointer steht, der auf die erste Adresse nach dem letzten festen Argument auf dem Stack der Funktion zeigt. Nach dem Casten auf den richtigen Typ kann man Variablen dieses Typs dereferenzieren. |
va_start | Funktionsmakro, das zwei Parameter erhält. Der erste Parameter ist ein Pointer vom Typ va_list, mit dem zweiten Parameter übergibt man die Länge der variablen Parameterliste. Mit diesen beiden Parametern kann va_start das Makro va_list mit dem richtigen Stackpointer initialisieren. |
va_arg | Funktionsmakro, das zwei Parameter erhält. Der erste Parameter ist ein Pointer vom Typ va_list, mit dem zweiten Parameter übergibt man den Typ der Argumente der variablen Parameterliste. Der Typ wird gebraucht um den Pointer zu casten und zu inkrementieren. |
va_end | Funktionsmakro, dem ein Pointer vom Typ va_list übergeben wird. Das Makro gibt Speicher frei, der während des Durchlaufs der Argumentenliste gebraucht wurde. |
va_copy | Funktionsmakro, das zwei Parameter erhält. Der Wert des zweiten Pointers wird in den ersten Pointer kopiert. Damit kann man die Liste (oder einenn Teil davon) ein zweites Mal durchlaufen. |
Die aktuellen Implementierung dieser Makros hängt vom verwendeten Compiler ab, da die Compiler den Stack unterschiedlich verwalten dürfen.
Die Funktion mittelwert() ermittelt den Mittelwert einer beliebig langen Reihe von double-Zahlen.
double mittelwert(int size, ...) { int i; double sum = 0; va_list sp; // Preprozessormacro definiert einen stackpointer (nicht initialisiert) va_start(sp, size); // initialisiert mit Hilfe des letzten festen Parameters den Stackpointer sp printf("*sp = %f\n", *((double*)sp) ); for(i=0; i<size; i++) { sum += va_arg(sp, double); //Requires the type to cast to. Increments sp to the next argument. printf("*sp = %f\n", *((double*)sp) ); } va_end(sp); // gibt Ressourcen frei return sum/size; }
Ein Aufruf der Form
int main(void) { puts("varargs"); // keine automatische Konvertierung von int nach double !! double erg = mittelwert(7, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); // falls es mehr Argumente sind werden sie ignoriert printf("average = %f\n", erg); return 0; }
ergibt
varargs *sp = 1.000000 *sp = 2.000000 *sp = 3.000000 *sp = 4.000000 *sp = 5.000000 *sp = 6.000000 *sp = 7.000000 average = 4.000000