Motivation: In diesem Abschnitt wird der Aufrauf eines Programmes aus Sicht des C-Programms und der Zugriff auf die angegebenen Optionen beschrieben. |
programmname parameter1 ... parameternParameter sind
An die main-Funktion werden Argumente übergeben. Das erste gibt die Anzahl der Aufrufparameter an (argc), das zweite die Adresse eines Feldes (argv).
Bezogen auf die Kommandozeile zum Aufruf des C-Compilers
cc -o prog prog.centhält argc den Wert 4, argv zeigt auf ein Feld mit 5 Zeigern. Dabei enthalten die einzelnen Feldelemente die Adressen der Zeichenketten cc, -o, prog und prog.c . Der Wert des letztes Zeigers ist NULL und spezifiziert damit das Ende der Parameterliste.
argv: [ * ] --> | [ * ] --> | "cc" |
[ * ] --> | "-o" | |
[ * ] --> | "prog" | |
[ * ] --> | "prog.c" | |
NULL |
Das Zeigerfeld und die Zeichenketten mit den Aufrufparametern werden grundsätzlich beim Start jedes Programms im Stack angelegt. Jedes Programm (im Beispiel ist das Programm der C-Compiler) kann darauf Bezug nehmen - muss dies aber nicht tun.
(Anmerkung: argv[n] ist ein Lvalue, der zum Adressraum des Prozesses gehört. Die Anweisung strcat(argv[2],argv[1]); führt deshalb weder beim Compilerlauf noch bei der unmittelbaren Ausführung zu einem Fehler. Es wird allerdings die Prozessumgebung verfälscht!)
Die Standardbibliothek stellt für die Auswertung der Argumente die Funktion getopt bereit:
int getopt(int argc, char **argv, char *optstring);
Die Parameter argc und argv besitzen die gleiche Bedeutung wie die gleichnamigen Parameter der main-Funktion. In optstring werden die möglichen Optionen angegeben. (z.B. "o")
In der gleichen Form wie die Parameter der Kommandozeile einem Programm bereitgestellt werden, werden auch alle Umgebungsvariablen der aufrufenden Shell (Kommandointerpreter) übergeben. Die Mainfunktion kann somit einen dritten Parametern auswerten:
BEISPIELE/b31a.c: #include <stdio.h> main(argc, argv) /* Argumente an main-Funktion */ int argc; char *argv[]; { int i; printf("Kommando: %s:\n", argv[0]); while (--argc) if (**++argv != '-') printf(" Arg. = %s\n", *argv); else for( i=1; (*argv)[i] != '\0'; i++) printf(" Flag = (%c)\n", (*argv)[i]); }
Die Parameter der main-Funktion sind fest vordefiniert, die Umgebungsvariablen werden immer als 3. Argument übergeben. Die verwendeten Bezeichner werden zwar häufig benutzt, sind aber prinzipiell frei wählbar.
VERBATIM/b31: main(argc, argv, env) int argc; char **argv, **env;
Der Zugriff auf einzelne Umgebungsvariablen ist analog dem oben beschriebenen Verfahren möglich.
Alternativ kann auch die Bibliotheksfunktion getenv() benutzt werden (siehe Kapitel 3.3.2). Das folgende Programm liest von der Standardeingabe und schreibt in die Standardausgabe. Dabei soll mit dem Flag -n die Nummerierung der Zeilen und mit dem Flag -v das Sichtbarmachen nichtdruckbarer Zeichen gesteuert werden können.
BEISPIELE/b31c.c: #include <stdio.h> main(argc, argv, env) /* Environment */ char *argv[], *env[]; { int i; i=0; while (env[i] != NULL) printf("%s\n",env[i++]); }
BEISPIELE/b31b.c: #include<stdio.h> #include<ctype.h> short vanz=0; main(argc,argv) /* Kopieren mit Zeilennummern */ int argc; char **argv; { void putline(); char zf[512]; char **argp,*opt,*getline(); short nanz=0; int znr=0; argp=argv; fprintf(stderr,"Filekopieren mit Zeilennr. (-n) (-v)\n\n"); while(--argc>0 && (*++argp)[0]== '-'){ for (opt=argp[0]+1;*opt!='\0';opt++){ switch(*opt){ case 'n' : nanz++; break; case 'v' : vanz++; break; default: fprintf(stderr,"%s bad argument \n",argp[0]); exit(1); } } } while(getline(zf)!=NULL){ if (nanz){ printf("%6d ",++znr); } putline(zf); } } char *getline(z) char *z; { int c; char *pz; pz=z; while((c=getchar())!=EOF){ if ((*pz++=c)=='\n') break; } if (c==EOF&&pz==z) return(NULL); *pz='\0'; return(pz); } void putline(z) char *z; { int c; while(c=*z++){ if (vanz&&isprint(c)==0) printf("\\%#o",c); else putchar (c); } if (vanz) putchar ('\n'); }