Praktisch alle Programme nehmen Parameter beim Programmstart entgegen, selbst die grafisch Orientierten (GUIs). In einem früheren Tutorial (Command Line Parameter Parsing) habe ich gezeigt, wie dieses Problem gelöst werden könnte. Dieses Tutorial zeigt nun, wie mit Hilfe der Functionen getopt und getopt_long
der Standard C Bibliothek dieses Problem angegangen werden kann.
Dieses Tutorial setzt genügend C Kenntnisse voraus um einfachere Programme zu schreiben, zu übersetzen und auszufüren.
Die Standardbibliothek stellt drei Funktionen zur Verfügung um Parameter zu parsen. Dies sind:
getopt
getopt_long
getopt_long_only
Dieses Kapitel geht kurz auf die Funktionen ein und erklärt deren Arbeitsweise, die Parameter und die Verwendung der Funktionen.
Diese Funktion wird dazu verwendet, Parameter einfacher Struktur wie z.B. -t
oder -h
zu erkennen. Parameter müssen mit einem -
beginnen. Parameter die ohne -
beginnen werden nicht als solche erkannt.
Um die Funktion getopt verwenden zu können, muss das Headerfile
eingefügt werden. Sie hat folgende Signatur:
als globale Variablen sind die folgenden im Einsatz:
Die ersten zwei Parameter sind jene, welche die Funktion main übernimmt.
Der Parameter const char * optstring
enthält die möglichen Parameter (je ein Zeichen). Folgt dem Zeichen ein Doppelpunkt :
, so erwartet der Parameter ein Argument. Bei zwei Doppelpunkten ::
ist das Argument Optional. Beispiele:
"abcd"
: Es sind die Parameter a
, b
, c
und d
möglich."abc:d"
: Es sind die Parameter a
, b
und d
möglich. Der Parameter c
erwartet ein Argument. Dies kann in zwei unterschiedlichen Formen angegeben werden:
-cARG
-c ARG
Auf das Argument kann über den Pointer char * optarg
zugegriffen werden."abc::d"
: Gleich wie bei "abc:d"
mit dem Unterschied, dass das Argument optional ist. Falls ein Argument angegeben wurde, so ist es auch über optarg zu erreichen.Die genaue Spezifikation sind der manpage zu entnehmen: getopt(3)
.
Im Gegensatz zu getopt welches Parameter in kurzer Form erkennt, ist getopt_long
in der Lage Parameter wie --help
oder --dir=foobar
zu verarbeiten. Es ist zwingend, dass vor dem Parameter zwei Striche stehen --
.
Das Headerfile:
muss dabei eingefügt sein. Die Signatur sieht wie folgt aus:
int getopt_long(int argc, char * const argv[], const char *optstring,
const struct option *longopts, int *longindex)
Die ersten drei Parameter sind gleich wie bei getopt. Die folgenden Parameter sind zusätzlich und dienen dazu die langen Parameter zu definieren. Die Struktur option (aus getopt.h
) sieht im Detail wie folgt aus:
Hier eine kurze erklärung. Für eine ausführliche ist die man page zu konsultieren.
Variable | Beschreibung |
---|---|
name |
Name des Parameters, z.B. “help” |
has_arg |
Spezifiziert ob der Parameter ein Argument erwartet. Mögliche Werte: no_argument , required_argument , optinal_argument |
flag |
Spezifiziert wie Resultate zurückgegeben werden sollen. Falls dieser Wert 0 ist, so wird val zurückgeliefert. Falls dieser Wert unterschiedlich von 0 ist, so wird val in die Variable gelegt, zu der flag zeigt (falls der Parameter nicht gefunden wurde, so bleibt die entsprechende Variable unverändert). |
val |
Der Wert, der von getopt_long zurückgegeben werden soll. Hier wird oft die Kurzform des Parameters angegeben, z.B. für help wird h angegeben. |
Mit Hilfe dieser Struktur können sehr einfach Parameter definiert werden (Ausschnitt aus getopt2.c
):
static const struct option long_options[] =
{
{ "AAA", no_argument, 0, 'a' },
{ "BBB", no_argument, 0, 'b' },
{ "CCC", required_argument, 0, 'c' },
{ "DDD", no_argument, 0, 'd' },
{ "EEE", no_argument, 0, 0 },
{ "FFF", required_argument, 0, 0 },
0
};
Speziell zu beachten gilt es die abschliessende 0. Sie dient dazu getopt_long
mitzuteilen, wann die Liste der möglichen Parameter zu Ende ist.
Der letzte Parameter der Funktion dient dazu den Index des gefundenen Parameters aufzunehmen.
Es ist dann sehr einfach die Funktion aufzurufen:
Diese Verwendungsweise, eine Kombination von optstring und der obigen Struktur, von getopt_long
hat den Vorteil, dass sowohl die langen Parameter (--AAA
, --BBB
, etc.) wie auch die Kurzen (-a
, -b
, etc.). Die möglichen Parameterformen als Übersicht (ARG
ist wieder das Argument):
Kurze Form mit -
-a
-ab
-c ARG
-cARG
-ac ARG
-acARG
Lange Form mit ‘–’
--AAA
--CCC ARG
--CCC=ARG
Natürlich ist auch eine Kombination von kurzen und langen Parametern möglich. Zu beachten ist jedoch, dass die lange Form immer ein --
und die kurze ein -
braucht um als solche identifiziert zu werden. Die kurze Form ist übrigens die Gleiche wie bei getopt.
getopt_long_only
funktioniert gleich wie getopt_long
, jedoch mit dem kleinen Unterschied, dass lange Parameter auch mit -
angegeben werden können, anstelle nur mit --
.
Die Signatur:
int getopt_long_only(int argc, char * const argv[], const char * optstring,
const struct option * longopts, int * longindex)
Da die Ähnlichkeit mit getopt_long
so gross ist, wird auf weitere Erklärungen verzichtet.
Dieses Kapitel enthält je ein Beispiel zu den Funktionen getopt und getopt_long
.
Weiter unten stehen die Programme als ganzes oder stehen auch bereit zum Download.
Zuerst die nötigen Headerfiles:
Für das Demoprogramm reicht eine Funktion:
Nun wollen wir parameter parsen, so lange wie Parameter spezifiziert sind. Die Variable optind
wird autmatisch von getopt
erhöht, so lange wie diese kleiner als die Anzahl spezifierter Parameter argc.
Alexander Dahl hat hier auf einen Fehler hingewiesen (besten Dank!): die Schleife sollte so aussehen:
damit das Umsortieren von Parametern funktioniert und solche Dinge möglich sind wie:
Als Erstes verwenden wir die genannte Funktion um herauszufinden, welcher Parameter angegeben wurde.
Ist das Resultat -1
so ist das Ende er Parameter erreicht, die durch getopt erkannt werden können. Für alle andern Werte wird dann auf der Zeile 10 unterschieden.
Bei einem Resultat von ?
handelt es sich um einen unbekannten Parameter.
Ein :
wird geliefert, falls ein Parameter der ein zwingendes Argument erwartet keines erhält.
Die folgenden vier Rückgabewerte entsprechen dem jeweiligen Parameter. Bei c
(Zeile 23/24) wird gezeigt, wie auf ein optionales oder zwingendes Argument zugegriffen werden kann.
case 'a':
printf("'a' was specified.\n");
break;
case 'b':
printf("'b' was specified.\n");
break;
case 'c':
printf("'c' was specified. Arg: `<%s>`\n", optarg);
break;
case 'd':
printf("'d' was specified.\n");
break;
Andere Rückgabewerte sind unbekannt.
Die obige Schleife (Zeile 6) kann Parameter verarbeiten die unmittelbar hinter dem Programmnamen angegeben werden. Beispiel:
Die folgende Schleife gibt alle folgenden Parameter aus. Achtung: sobald ein Parameter angegeben wird, der nicht in optstring
definiert wird, so bricht getopt
ab und es werden alle folgenden Parameter in der zweiten Schleife (Zeile 33) ausgegeben. Beispiel:
Nun also die Schleife:
Das Ende der Funktion hat keinen Bedarf weiterer Erklärungen.
Zuerst wieder die nötigen Headerfiles:
Wie gehabt: für dieses kleine Tutorial genügt uns eine Funktion.
Nun die Definition der langen Parameter. Die Struktur wurde ja schon in Kapitel 2.2 erklärt.
static const struct option long_options[] =
{
{ "AAA", no_argument, 0, 'a' },
{ "BBB", no_argument, 0, 'b' },
{ "CCC", required_argument, 0, 'c' },
{ "DDD", no_argument, 0, 'd' },
{ "EEE", no_argument, 0, 0 },
{ "FFF", required_argument, 0, 0 },
0
};
Wir benötigen wiederum eine Schleife, die solange auf Parameter testet wie auf der Kommandozeile angegeben wurde (maximal):
Hier auch die Endlosschleife wie oben beschrieben.
Ein paar lokale Variablen erleichtern uns das Leben.
Schon gehts ans Eingemachte. Wie in Kapitel 2.2 erwähnt bedienen wir uns einer Kombination von optstring und der Struktur option um lange und kurze Parameter zuzulassen.
Das Ende der Liste ist erreicht, also die while-Schleife (Zeile 16) verlassen.
Die Auswertung des Resultats präsentiert sich analog zu der bei getopt:
Dieser Fall kann aus zwei Gründen auftreten: es wurde entweder die kurze Form angegeben (-a
) oder es wurde die lange Form angegeben (--AAA
). Dies wird ermöglicht durch die Definition des langen Parameters (Zeile 8) oder durch den optstring
(Zeile 21). Für die nächsten drei Parameter gilt das Selbe.
case 'a': /* same as index==0 */
printf("'a'/'AAA' was specified.\n");
break;
case 'b': /* same as index==1 */
printf("'b'/'BBB' was specified.\n");
break;
case 'c': /* same as index==2 */
printf("'c'/'CCC' was specified. Arg: `<%s>`\n",
optarg);
break;
case 'd': /* same as index==3 */
printf("'d'/'DDD' was specified.\n");
break;
Dies ist ein Spezialfall: die Parameter EEE
und FFF
besitzen keine Kurzform. In der obigen Struktur (Zeilen 12/13) haben wir angegeben, dass als result der Wert 0
geliefert werden soll falls einer dieser Parameter angegeben wurde. Natürlich hätten wir auch eindeutige Rückgabewerte definieren können.
In den folgenden Zeilen wird gezeicht, wie mit Hilfe der Variable index (gesetzt von getopt_long
) auf die entsprechende Parameterdefinition zugegriffen werden kann.
case 0: /* all parameter that do not */
/* appear in the optstring */
opt = (struct option *)&(long_options[index]);
printf("'%s' was specified.",
opt->name);
if (opt->has_arg == required_argument)
printf("Arg: `<%s>`", optarg);
printf("\n");
break;
Auf den Rest des Programms wird nicht weiter eingegangen, da dies schon in Kapitel 3.1 erklärt wurde.
default: /* unknown */
break;
}
}
/* print all other parameters */
while (optind < argc)
{
printf("other parameter: `<%s>`\n", argv[optind++]);
}
return 0;
}
Dieses Kapitel enhält nochmals die vollständigen Programme ohne die eingestreuten Kommentare.
#include <stdio.h>
#include <unistd.h>
int main(int argc, char ** argv)
{
while (1)
{
int result = getopt(argc, argv, "abc:d");
if (result == -1) break; /* end of list */
switch (result)
{
case '?': /* unknown parameter */
break;
case ':': /* missing argument of a parameter */
fprintf(stderr, "missing argument.\n");
break;
case 'a':
printf("'a' was specified.\n");
break;
case 'b':
printf("'b' was specified.\n");
break;
case 'c':
printf("'c' was specified. Arg: <%s>\n", optarg);
break;
case 'd':
printf("'d' was specified.\n");
break;
default: /* unknown */
break;
}
}
while (optind < argc)
{
printf("other parameter: <%s>\n", argv[optind++]);
}
return 0;
}
#include <stdio.h>
#include <getopt.h>
int main(int argc, char ** argv)
{
static const struct option long_options[] =
{
{ "AAA", no_argument, 0, 'a' },
{ "BBB", no_argument, 0, 'b' },
{ "CCC", required_argument, 0, 'c' },
{ "DDD", no_argument, 0, 'd' },
{ "EEE", no_argument, 0, 0 },
{ "FFF", required_argument, 0, 0 },
0
};
while (1)
{
int index = -1;
struct option * opt = 0;
int result = getopt_long(argc, argv,
"abc:d",
long_options, &index);
if (result == -1) break; /* end of list */
switch (result)
{
case 'a': /* same as index==0 */
printf("'a'/'AAA' was specified.\n");
break;
case 'b': /* same as index==1 */
printf("'b'/'BBB' was specified.\n");
break;
case 'c': /* same as index==2 */
printf("'c'/'CCC' was specified. Arg: <%s>\n",
optarg);
break;
case 'd': /* same as index==3 */
printf("'d'/'DDD' was specified.\n");
break;
case 0: /* all parameter that do not */
/* appear in the optstring */
opt = (struct option *)&(long_options[index]);
printf("'%s' was specified.",
opt->name);
if (opt->has_arg == required_argument)
printf("Arg: <%s>", optarg);
printf("\n");
break;
default: /* unknown */
break;
}
}
/* print all other parameters */
while (optind < argc)
{
printf("other parameter: <%s>\n", argv[optind++]);
}
return 0;
}
Alle source code Files die auf dieser Seite publiziert werden, sind frei zu kopieren, modifizieren, weiterverbreiten und zu verwenden.
Das Copyright des Tutorials liegt bei Mario Konrad.