18.3 »vprintf()«, »vsprintf()«, »vfsprintf()« und »vsnsprintf()« 

Mit dem Makro va_arg werden die variablen Parameter einzeln verarbeitet. Mit den beiden Funktionen vprintf() und vfprintf() kann die ganze Liste in einem Stück übernommen werden. Dazu wird der Makroname va_arg nicht mehr benötigt. Hier sehen Sie die Syntax von vprintf():
#include <stdio.h> #include <stdarg.h> int vprintf(const char * restrict format, va_list artPtr);
Jetzt soll hiermit die Funktion printf() nachgebildet werden. Der Code sieht so aus:
/* my_printf.c */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> static void myprintf(char *string, ...) { va_list argzeiger; va_start(argzeiger,string); vprintf(string,argzeiger); va_end(argzeiger); } int main(void) { char hallo[] = "Hallo vprintf\n"; myprintf("Hier ein Beispiel von vprintf...."); myprintf("\n"); myprintf("%d * %d = %d\n",10,10,10*10); myprintf("%s",hallo); return EXIT_SUCCESS; }
Der einzige Unterschied zu den vorigen Beispielen ist, dass hier anstatt va_arg() die Funktion vprintf() benutzt wird. Diese Funktion übernimmt den ganzen String in einem Stück. Natürlich macht dieses Programm wenig Sinn. vprintf() eignet sich sehr gut, um eigene Fehlermeldungsroutinen zu schreiben. Ein Beispiel:
/* error_handling.c */ #include <stdio.h> #include <stdarg.h> #include <stdlib.h> #define MAXWERT 8192 enum{ WARN, ERROR, EXIT, MISC }; /* Stringtabelle mit Fehlerausgaben */ const char *error[] = { "Fehlerhafte Eingabe\n", "Maximaler Wertebereich ueberschritten\n", "Nagativer Wert wurde eingegeben\n" }; void fehler(int kennung, const char *format, ...) { va_list vargzeiger; va_start(vargzeiger,format); switch(kennung) { case 0 : printf("\nAchtung: "); vprintf(format,vargzeiger); break; case 1 : printf("\nFehler : "); vprintf(format,vargzeiger); break; case 2 : printf("\nProgrammabbruch : "); vprintf(format,vargzeiger); exit(EXIT_FAILURE); case 3 : vprintf(format,vargzeiger); break; default : printf("\nFalscher Funktionsaufruf\n"); } va_end(vargzeiger); } int main(void) { int zahl, ret; printf("Eine Zahl zwischen 0-8192: "); ret=scanf("%d",&zahl); /* fehlerhafte Eingabe vorgenommen */ if(ret == 0) fehler(EXIT, error[0]); /* Zahl größer als Maximalwert */ else if(zahl > MAXWERT) fehler(WARN, error[1]); /* negative Zahl */ else if(zahl < 0) fehler(ERROR, error[2]); /* alles in bester Ordnung */ else fehler(MISC, "Eingabe ist in Ordnung\n"); return EXIT_SUCCESS; }
Damit kann jederzeit mit dem Funktionsaufruf
fehler(kennungsnummer,"Fehler - Unbekannter Fehler");
eine bestimmte Fehlermeldung auf dem Bildschirm ausgegeben werden – je nachdem, welche Kennungsnummer an die Funktion fehler() übergeben wurde. In diesem Beispiel wurden die Fehlernummern in enum-Variablen gekleidet und die entsprechende Fehlerausgabe in eine Stringtabelle.
Das dateiorientierte Gegenstück zu vprintf() ist die Funktion vfprintf() mit folgender Syntax:
#include <stdio.h> #include <stdarg.h> int vfprintf( FILE * restrict f, const char * restrict puffer, va_list argPtr);
Diese Funktion ist gleichbedeutend mit der Funktion vprintf(), nur dass Sie dabei noch formatiert in einen Stream oder aber auch auf die Standardausgabe schreiben können mit:
vfprintf(stdout, format, vargzeiger); // gleichwertig zu ... vprintf(format, vargzeiger);
Zudem existiert noch die Funktion vsprintf(), die ähnlich wie sprintf() funktioniert. Ihre Syntax lautet:
#include <stdio.h> #include <stdarg.h> int vsprintf( const char * restrict puffer, const char * restrict format, va_list argPtr);
Damit kann eine variabel lange Argumentliste formatiert in einen String geschrieben werden. Hier sehen Sie ein kurzes Beispiel:
/* vsprintf.c */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> /* Bei Linux die Bibliothek math.h extra hinzulinken (-lm) * gcc -o programm programm.c -lm */ #include <math.h> static void float2string(char *string, char *dezimal, ...) { va_list argzeiger; va_start(argzeiger,dezimal); vsprintf(string,dezimal,argzeiger); va_end(argzeiger); } int main(void) { char string[100]; float zahl = 20.0; float2string(&string[0],"string-> %.6f <-string",sqrt(zahl)); printf("%s\n",string); return EXIT_SUCCESS; }
Ab dem C99-Standard ist mit vsnprintf() auch die snprintf()-Alternative mit einer variablen Argumentliste neu hinzugekommen. Die Syntax dieser Funktion sieht so aus:
#include <stdio.h> #include <stdarg.h> int vsnprintf( const char * restrict puffer, size_t n const char * restrict format, va_list argPtr );
Zwar wurden die Funktionen vprintf(), vfprintf(), vsprintf() und vsnsprintf() recht kurz abgehandelt, aber im Grunde arbeiten all diese Funktionen auf die gleiche Art und Weise wie ihre Gegenstücke printf(), fprintf(), sprintf() und snprintf(), nur dass der letzte Parameter immer ein Argumentzeiger vom Typ va_list ist, womit zusätzlich zur bereits vorhandenen Funktion der Gegenstücke auch noch optionale Argumente möglich sind. Um die Argumentliste verwenden zu können, muss diese immer zuerst mit va_start() initialisiert und am Ende mit va_end() beendet werden. va_arg() wird hier nicht benötigt, weil dieses Makro intern von den Funktionen verwendet wird.
Hinweis |
Die Funktionen gibt es auch wieder für breite Zeichen. In diesem Fall wären dies vwprintf(), vfwprintf() und vswprintf(). |
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.