Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
Vorwort des Gutachters
1 Einstieg in C
2 Das erste Programm
3 Grundlagen
4 Formatierte Ein-/Ausgabe mit »scanf()« und »printf()«
5 Basisdatentypen
6 Operatoren
7 Typumwandlung
8 Kontrollstrukturen
9 Funktionen
10 Präprozessor-Direktiven
11 Arrays
12 Zeiger (Pointer)
13 Kommandozeilenargumente
14 Dynamische Speicherverwaltung
15 Strukturen
16 Ein-/Ausgabe-Funktionen
17 Attribute von Dateien und das Arbeiten mit Verzeichnissen (nicht ANSI C)
18 Arbeiten mit variabel langen Argumentlisten – <stdarg.h>
19 Zeitroutinen
20 Weitere Headerdateien und ihre Funktionen (ANSI C)
21 Dynamische Datenstrukturen
22 Algorithmen
23 CGI mit C
24 MySQL und C
25 Netzwerkprogrammierung und Cross–Plattform-Entwicklung
26 Paralleles Rechnen
27 Sicheres Programmieren
28 Wie geht’s jetzt weiter?
A Operatoren
B Die C-Standard-Bibliothek
Stichwort

Buch bestellen
Ihre Meinung?

Spacer
<< zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch
Buch: C von A bis Z

C von A bis Z
3., aktualisierte und erweiterte Auflage, geb., mit CD und Referenzkarte
1.190 S., 39,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1411-7
Pfeil 18 Arbeiten mit variabel langen Argumentlisten – <stdarg.h>
Pfeil 18.1 Makros in <stdarg.h> – »va_list«, »va_arg«, »va_start« und »va_end«
Pfeil 18.2 Die Argumentliste am Anfang oder Ende kennzeichnen
Pfeil 18.3 »vprintf()«, »vsprintf()«, »vfsprintf()« und »vsnsprintf()«
Pfeil 18.4 Variadic Makros – __VA_ARGS__


Rheinwerk Computing - Zum Seitenanfang

18.4 Variadic Makros – __VA_ARGS__ topZur vorigen Überschrift

Ab dem C99-Standard haben Sie die Möglichkeit, ein Makro mit variablen Argumenten zu definieren und aufzurufen. Zugegeben, dieser Abschnitt hätte auch gut zu Kapitel 10, »Präprozessor-Direktiven«, gepasst, aber ich habe mich dann doch entschieden, dieses Thema hier aufzunehmen.

Das Prinzip ist denkbar einfach. Beim Aufruf eines Makros fasst der Präprozessor alle optionalen Argumente zu einem Argument zusammen. Hierzu wurde der Bezeichner __VA_ARGS__ eingeführt, der im Ersatztext die zusammengefassten optionalen Argumente enthält. Allerdings darf der Bezeichner __VA_ARGS__ nur im Ersatztext der Makrodefinition verwendet werden. __VA_ARGS__ kann dort wie fast ein gewöhnlicher Parameter verwendet werden. Der Unterschied ist, dass der Parameter durch sämtliche Argumente ersetzt wird und nicht nur durch ein Argument.

Hier folgt ein einfaches Beispiel dafür, wie Sie ein Makro erstellen können, das eine variable Anzahl von Argumenten verwendet:

/* variadic1.c */
#include <stdio.h>
#include <stdlib.h>
#define errprintf(...) fprintf(stderr, __VA_ARGS__)
int main(void) {
   const char str[] = "ein Argument";
   int val = 10;

   errprintf("Hallo Welt %d %s\n", val, str);
   errprintf("Fehler!! Zeile: %d (%s)\n",
      __LINE__, __DATE__ );
  return EXIT_SUCCESS;
}

Das Prinzip ist recht einfach. Der Makroaufruf

errprintf("Hallo Welt %d %s\n", val, str);

sieht nach dem Ersetzen des Textes in __VA_ARGS__ wie folgt aus:

fprintf(stderr, "Hallo Welt %d %s\n", val, str);

Anstatt die Ausgabe auf den Standard-Stream stderr auszugeben, können Sie selbstverständlich auch eine Datei dafür verwenden – vorausgesetzt natürlich, Sie haben eine entsprechende Datei mit FILE-Zeiger zum Schreiben geöffnet. Dies ist ein eleganter und einfacher Weg, um ein Programm mitzuprotokollieren, indem bestimmte Dinge in einer Logdatei geschrieben werden.

Hierzu ein weiteres Beispiel, das noch einige Möglichkeiten demonstrieren soll, ein Makro mit variablen Argumenten zu nutzen:

/* variadic2.c */
#include <stdio.h>
#include <stdlib.h>

#define fprintf_log(...) fprintf(fp, __VA_ARGS__)
#define errprintf(...) fprintf(stderr, __VA_ARGS__)
#define checkerror(x, ...) if(!(x)) { \
                             fprintf(stderr, __VA_ARGS__); }
#define LOGFILE "logfile.txt"

static FILE *fp;

void openLog(void) {
   fp = fopen(LOGFILE, "w+");
   if( NULL == fp ) {
      errprintf("%s:%d: Konnte Logdatei nicht oeffnen\n",
         __func__, __LINE__);
      exit(EXIT_FAILURE);
   }
}
int main(void) {
   char name[80];
   int val, check;

   openLog();
   fprintf_log("(%s/%s): Programmstart\n",
      __DATE__, __TIME__);

   printf("Bitte Namen eingeben: ");
   fgets( name, 80, stdin);
   // Die Eingabe wird mitprotokolliert.
   fprintf_log("Eingabe \"name\": %s", name);

   printf("Bitte eine Ganzzahl eingeben: ");
   check = scanf("%d", &val);
   // Wird nur ausgeführt, wenn die
   // Eingabe bei scanf() falsch war.
   checkerror(check, "Die Eingabe war falsch\n");

   return EXIT_SUCCESS;
}

Mit dem ersten Makro

#define fprintf_log(...) fprintf(fp, __VA_ARGS__)

können Sie eine variable Anzahl von Argumenten in den Stream fp schreiben – vorausgesetzt natürlich, der Stream fp wurde vorher zum Schreiben geöffnet, was in diesem Beispiel in der Funktion openLog() realisiert wurde. Mit fprintf_log() können Sie somit alles im Programm mitprotokollieren, was Ihnen sinnvoll erscheint.

Ebenfalls recht praktisch ist das folgende Makro:

#define checkerror(x, ...) if(!(x)) { \
                             fprintf(stderr, __VA_ARGS__); }

Hier wurde noch ein zusätzlicher Parameter verwendet, womit anschließend mit if überprüft wird, ob das Makro überhaupt ausgeführt werden soll. In diesem Fall wird das Makro nur dann ausgeführt, wenn der zusätzliche Parameter x gleich 0 ist. Im Listing wurde dies bei der scanf()-Eingabe verwendet:

   int check;
   check = scanf("%d", &val);
   checkerror(check, "Die Eingabe war falsch\n");

Wurde bei scanf() eine falsche Eingabe gemacht, beispielsweise ein Zeichen anstatt einer Ganzzahl eingegeben, ist der Wert von check gleich 0. Und beim Aufruf von checkerror() wird dieser scanf()-Rückgabewert als erster Parameter übergeben. Somit würde das Makro checkerror() im Falle eines Fehlers nach der Ersetzung wie folgt aussehen:

if(!(check)) {
   fprintf(stderr, "Die Eingabe war falsch\n");
}

Im selben Verzeichnis wie das Listing variadic2.c finden Sie außerdem noch die Logdatei logfile.txt, die Sie nach Beendigung des Programms in einem Editor Ihrer Wahl betrachten können.


Hinweis

Auch hier muss man wieder erwähnen, dass dieses Makro mit variabel langen Argumenten nur mit Compilern funktioniert, die den C99-Standard erfüllen. Hier ist der GNU-GCC unter Linux vorbildlich. Microsoft VC++ beispielsweise kann mit solchen Makros noch nicht umgehen. Es bleibt zu hoffen, dass hier der Standard mit der kommenden 2010er-Version auch komplett implementiert wird.




Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
<< zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z

 C von A bis Z
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: C/C++






 C/C++


Zum Katalog: Einstieg in C






 Einstieg in C


Zum Katalog: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Katalog: C++ Handbuch






 C++ Handbuch


Zum Katalog: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2009
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de