getopt() aus dem POSIX-Standard
Bei wenigen Optionen kann man das Parsing von Hand implementieren. Sobald jedoch viele Optionen, insbesondere mit Kurz- und Langform, hinzukommen, wird das schnell unübersichtlich. Hier empfiehlt sich eine Bibliothek. Der POSIX-Standard stellt dafür getopt() (nur Kurzoptionen) und getopt_long() (mit Unterstützung für Langoptionen) bereit. Diese Funktionen übernehmen das sequenzielle Parsen von argv, erkennen Optionen und weisen ihnen gegebenenfalls Argumente zu. Die eigentliche Semantik (was mit einer erkannten Option passiert) bleibt Aufgabe des Programms.
Beispiel:
- Das Programm erwartet genau einen Dateinamen als positionsbasiertes Argument.
- Optional kann mit
-voder--verboseein ausführlicher Modus aktiviert werden.
Dafür definieren wir eine Struktur:
struct Options {
bool verbose;
const char *filename;
};
getopt_long() Wird mit einer Tabelle initialisiert und arbeitet wie ein zustandsbehafteter Iterator: Man ruft die Funktion wiederholt auf, bis sie -1 zurückgibt. Intern verarbeitet sie jeweils so viele Elemente aus argv, wie für die aktuelle Option nötig sind. Das Programm muss sich nicht selbst um den aktuellen Index kümmern.
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
typedef struct {
bool verbose;
const char *filename;
} Options;
int main(int argc, char **argv) {
Options opts = {
.verbose = false,
.filename = nullptr
};
static const struct option long_options[] = {
{ "verbose", no_argument, nullptr, 'v' },
{ nullptr, 0, nullptr, 0 }
};
for (int c; (c = getopt_long(argc, argv, "v", long_options, nullptr)) != -1;) {
switch (c) {
case 'v':
opts.verbose = true;
break;
case '?':
// getopt hat bereits eine Fehlermeldung ausgegeben
return 1;
}
}
// verbleibende Positionsargumente
if (optind >= argc) {
puts("Dateiname fehlt");
return EXIT_FAILURE;
}
opts.filename = argv[optind];
// ab hier normale Programmlogik
if (opts.verbose) {
puts("Verbose-Modus aktiv");
}
printf("Datei: %s\n", opts.filename);
}
Die Einträge des Arrays verdienen einen genaueren Blick:
- Name der Langoption (hier
"verbose", wird bei--verboseerkannt). - Ob die Option ein Argument erwartet:
no_argument(0) → kein Argument,required_argument(1) → Pflichtargument,optional_argument(2) → optionales Argument.
- Flag-Zeiger: meist
nullptr. Wenn man hier einen Zeiger auf eineint-Variable setzt, schreibtgetopt_longden Wert aus dem vierten Feld in diese Variable und gibt selbst0zurück. - Rückgabewert: Hier
'v'. Da das Flag-Feldnullptrist, gibtgetopt_longdiesen Wert zurück, wenn die Option gefunden wird. Gleichzeitig entspricht er der Kurzoption-v.
Der letzte Eintrag mit lauter nullptr/0 markiert das Ende der Tabelle.
Die globale Variable optind zeigt nach Beendigung der Schleife auf das erste nicht als Option verarbeitete Argument. Alles davor wurde von getopt_long() konsumiert (einschließlich etwaiger Argumente zu Optionen). So kann man einfach auf die verbleibenden positionsbasierten Argumente zugreifen.