Axel Rogat
Betriebssysteme und betriebssystemnahes Programmieren
 
3.2.6: DOS-Aufrufe Kapitel 3 4.1: Prozeß-Begriff 
 
  3.3 Aufrufparameter und Environment  
 

Ein Programm erhält auf zwei einfache Weisen schon beim Start Informationen - über Parameter aus der Kommandozeile und über Umgebungsvariablen. Die Mechanismen stammen zwar ursprünglich aus UNIX, sind mittlerweile aber in die ANSI-C-Definition eingegangen und funktionieren daher auch unter MS-DOS, auf dem AMIGA, etc.

3.3.1 Aufrufparameter

Beim Start eines Programms über eine Kommandozeile werden Angaben hinter dem Programmnamen als Parameter an das Programm interpretiert.

Die Aufrufzeile selbst ist ein String, der aber vom Startup-Code, der z.B. C- und C++-Programmen automatisch zugelinkt wird, aufbereitet wird. Die Zeile wird durch Folgen von Spaces oder Tabulatoren in Worte zerlegt. Wenn ein Wort Spaces enthalten soll, müssen Anführungszeichen gesetzt werden. Diese Worte werden der main-Funktion als Parameter übergeben:

int main(int argc, char *argv[]);
argc (argument count) enthält die Anzahl der Worte inklusive dem Programmnamen. Das Array argv (argument vector) enthält die eigentlichen Worte. argv[0] ist immer der Programmname. Die Variablen dürfen natürlich anders benannt werden, diese Schreibweise hat sich aber eingebürgert und ist deshalb immer gut lesbar.

Beim Aufruf

myprog say "hello world!"
ist also argc=3, argv[0]="myprog", argv[1]="say" und argv[2]="hello world!".

Die Parameter werden vom System immer wie reine Strings behandelt. Wenn sie z.B. numerisch interpretiert werden sollen, muß das explizit im Programm selbst geschehen (mit atoi, etc.)!

Der Rückgabewert des Hauptprogramms (immer vom Typ int) kann von dem Programm verwendet werden, der dieses Programm aufgerufen hat, unter UNIX beispielsweise die Shell (dazu später genauer).

Beispiel: Folgendes Programm gibt alle Bestandteile der Kommandozeile aus, ohne sie irgendwie zu interpretieren:

#include <iostream.h> int main(int argc, char *argv[]) { for (int i=1;i<argc;++i) cout << i << ": " << argv[i] << endl; return 0; }
Zur Interpretation von Parametern, etwa als Optionen (eingeleitet mit `-' bzw. `/'), kommen wir im Abschnitt über Shell-Kommandos.

Wenn man die Parameter ignorieren möchte, kann man folgenden alternativen Prototypen verwenden:

int main(void); /* in C++ kann das void entfallen*/

3.3.2 Environment

Ein Programm erhält Informationen über seine Umgebung, also über Benutzer, Pfade bestimmter wichtiger Verzeichnisse, Shells, Terminal und Bildschirm etc., in Form einer Liste von Paaren "Name/Wert", die als "Environment" bezeichnet wird.

Ein einzelner Eintrag wird auch als "Umgebungsvariable" bezeichnet. Mit Shell-Kommandos oder von Programmen aus kann man die Werte der Variablen verändern und abfragen, sowie neue Variablen anlegen.

Die Variablen haben für den Betriebssystem-Kern keine Bedeutung. Sie entsteht erst durch die Interpretation durch die Anwendungen, z.B. Shell, Compiler, Manual-Browser, etc.

Der Mechanismus ist zwar systemunabhängig, Namen und Bedeutung der Variablen ist aber nicht in ANSI-C festgelegt. Die Umgebung unter UNIX sieht völlig anders aus als die unter MS-DOS.

Der UNIX-Befehl env ohne Parameter gibt alle Umgebungsvariablen aus. Seine Ausgabe könnte wie folgt beginnen:

HOSTNAME=vulcan DISPLAY=:0.0 PATH=/sbin:/usr/sbin:/home/axel/bin: ...
Einige typische UNIX-Umgebungsvariablen sind folgende:

HOME das Heimatverzeichnis des jeweiligen Benutzers
PATH Liste von Pfaden, in denen nach ausführbaren Programmen (und Skripten) gesucht werden soll (mit `:' getrennt)
LOGNAME der Benutzername des jeweiligen Benutzers
SHELL der Pfad der Standard-Shell des Benutzers
PWD der (absolute) Pfad des aktuellen Verzeichnisses
TERM Typ des aktuellen Terminals (z.B. xterm oder vt100)
MANPATH Liste von Pfaden, die Manual-Seiten enthalten
DISPLAY ID des X-Window-Displays, auf dem standardmäßig Fenster geöffnet werden sollen
PRINTER Standard-Drucker, z.B. lp

Zu MS-DOS-Umgebungsvariablen siehe den Abschnitt zu COMMAND.COM am Ende des Kapitels.

Der Startup-Code übernimmt die Aufgabe, die interne System-Liste in ein Format umzusetzen, das von C aus günstig zu verwenden ist:

C-Programme erhalten eigentlich immer drei Parameter, von denen der letzte aber meist ignoriert wird:

int main(int argc, char *argv[], char *envp[]);
Es handelt sich bei ihm um ein weiteres String-Array - eines, das stringweise die Umgebungsvariablen enthält. Der letzte char* ist der Null-Pointer, um das Ende des Arrays zu markieren.

Außerdem gibt es eine globale Variable environ (deklariert in stdlib.h), die ebenfalls auf dieses Array zeigt:

extern char **environ;
Wenn man außerhalb von main das Array benötigt, wird man deshalb meistens environ verwenden.

Beispiel: Folgendes C++-Programm gibt das Environment zweimal aus - auf die beiden angedeuteten Weisen:

#include <iostream.h> #include <stdlib.h>

int main(int argc, char *argv[], char *envp[]) { for ( int i=0 ; envp[i]!=0 ; ++i ) cout << envp[i] << endl;

char **e=environ; while (*e!=0) cout << *e++ << endl;

return 0; }

Man beachte, daß es kein Analogon zu argc gibt, sondern daß das Array-Ende durch den Null-Pointer gekennzeichnet wird!

Folgende vier Funktionen (aus stdlib.h) können in Programmen verwendet werden, um Umgebungsvariablen zu lesen, setzen, anzulegen und zu löschen:

UNIX/DOS
char *getenv(const char *name);
  liest den Wert der Umgebungsvariable name. Man darf den String, auf den ein Pointer zurückgegeben wird, nicht modifizieren, sondern muß erst eine Kopie anlegen!
int putenv(const char *string);
  nimmt string in das Environment auf. Der String muß das Format "name=wert" haben. Eine existierende Variable name wird überschrieben. Es wird 0 (okay) oder -1 (Fehler) zurückgegeben.
int setenv(const char *name, const char *value, int overwrite);    /*nicht unter DOS/SVR4!*/
  setzt die Variable name auf den Wert value, d.h. ein Eintrag "name=value" wird angelegt. Eine existierende Variable name wird nur überschrieben, falls overwrite!=0.
void unsetenv(const char *name);   /*nicht unter DOS/SVR4!*/
  entfernt die Variable name aus dem Environment.

Beispiel: So kann man in UNIX die Identität des Benutzers ausgeben:

cout << "you are " << getenv("USER") << '@' << getenv("HOSTNAME") << endl;
Die Ausgabe ist z.B.: "you are axel@vulcan".

 
3.2.6: DOS-Aufrufe Startseite 4.1: Prozeß-Begriff