20.3 vprintf, vsprintf und vfsprintf
 
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 die Syntax von vprintf():
int vprintf(char *format, va_list name);
Jetzt soll hiermit die Funktion printf() nachgebildet werden. Der Code:
/* 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 *f, const char *puffer, va_list arg);
Diese Funktion ist gleichbedeutend mit der Funktion vprintf(), nur dass Sie dabei noch formatiert in einem 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 funktioniert wie sprintf(). Die Syntax:
#include <stdio.h>
#include <stdarg.h>
int vsprintf(const char *puffer,const char *format,
va_list argzeiger);
Damit kann eine variabel lange Argumentliste formatiert in einen String geschrieben werden. Ein kurzes Beispiel:
/* vsprintf.c */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
/* Bei Linux 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;
}
|