FAQ:Systemabhängiges

[ FAQ in de.comp.lang.c ]


Diese FAQ bezieht sich in ihrer Gänze auf den inzwischen nicht mehr aktuellen ISO-C Standard 9899:1990, vielfach auch als C90 bezeichnet. Der seit Dezember 1999 existierende neue ISO 9899:1999 Standard (oder auch C99) wird nicht berücksichtigt.


[ Inhalt ][ Index ][ ZurÜck ][ Weiter ]


Frage 16.1: Wie kann ich einen einzelnen Buchstaben von der Tastatur auslesen, ohne auf RETURN zu warten?

Antwort: Im Gegensatz zum allgemeinen Glauben und den Wünschen vieler Programmierer ist dies keine C-Frage. (Genauso wenig wie ähnliche Fragen, die das ECHO von Tastatur-Eingaben betreffen.) Der Transport von Buchstaben von einer "Tastatur" zu einem C-Programm ist eine Funktion des entsprechenden Betriebssystems, und wurde nicht durch die Sprache C standardisiert. Manche Versionen von CURSES haben die Funktion cbreak(), welche diese Funktionalität beinhaltet. Um speziell ein kurzes Paßwort ohne ECHO einzulesen, kann getpass() verwendet werden. Unter UNIX kann IOCTL verwendet werden, um die Terminal-Treiber-Modi zu verändern (CBREAK oder RAW bei "klassischen" Versionen; ICANON, c_cc[VMIN] und c_cc[VTIME] bei System V- oder POSIX-Systemen). Unter MSDOS kann getch() benutzt werden. Bei VMS sollten die Bildschirmsteuerungs-Routinen (SMG$) oder CURSES benutzt oder systemnahe $QIOs mit den IO$_READVBLK (und vielleicht IO$M_NOECHO) Funktionscodes verwendet werden, um einzelne Zeichen abzufragen. Bei anderen Systemen müssen entsprechende Funktionen selbst entwickelt werden. Man sollte beachten, dass manche Betriebssysteme es generell nicht erlauben, da das Einlesen der Zeichen in Eingabezeilen durch seperate Prozessoren erfolgt, die nicht der direkten Kontrolle der CPU unterstehen, auf der das Programm läuft.

Betriebssystemspezifische Fragen sind in de.comp.lang.c nicht angebracht. Viele dieser Fragen werden in FAQs der Gruppen comp.unix.questions, comp.os.msdos.programmer usw. beantwortet. Viele Antworten sind nicht einmal zwischen verschiedenen Betriebssystemvarianten gleich. Man sollte bedenken, dass die Beantwortung von betriebssystemspezifischen Fragen auf anderen Systemen anders ausfallen kann, als auf dem eigenen.

Querverweise: PCS Sek. 10 S. 128-9, Sek. 10.1 S. 130-1.


Frage 16.2: Wie finde ich heraus, ob Zeichen zum Einlesen zur Verfügung stehen (und wenn, wieviele)? Oder wie kann ich Zeichen einlesen, ohne dass mein Prozeß blockiert, wenn keine da sind?

Antwort: Dies ist ebenfalls eine völlig betriebssystemspezifische Frage. Manche Version von CURSES haben die nodelay() Funktion. Abhängig vom System kann ebenso "nichtblockierende I/O" verwendet werden, oder ein Systemaufruf namens "select" oder der FIONREAD IOCTL-Aufruf oder kbhit() oder rdchk() oder die O_NDELAY Option für open() oder fcntl().


Frage 16.3: Wie kann ich den Bildschirm löschen? Wie kann ich Text invers darstellen?

Antwort: So etwas hängt vom verwendeten Terminaltyp (oder dem Bildschirm) ab. Zur Lösung des Problems kann eine Bibliothek wie TERMCAP oder CURSES, oder einige systemspezifische Routinen verwendet werden.


Frage 16.4: Wie lese ich die Maus aus?

Antwort: Hierüber informiert die Systembeschreibung oder eine geeignete systemspezifische Newsgruppe (deren FAQ man zunächst anschauen sollte). Die Maussteuerung ist beim X11-Window-System, MS-DOS, Macintosh und vermutlich jedem anderen System völlig verschieden.


Frage 16.5: Wie kann mein Programm den kompletten Pfadnamen der ausführbaren Datei ermitteln, von der es aufgerufen wurde?

Antwort: argv[0] könnte den ganzen Pfadnamen oder einen Teil davon beinhalten, oder auch gar nichts. Man kann die Such-Pfad Logik des Befehlsinterpreters kopieren, wenn der Name in argv[0] zwar vorhanden, aber nicht komplett ist. Es gibt aber keine garantierte oder portable Lösung.

Anmerkung von Uz::
Es gibt ein Paket namens selfdir, dass es z.B. irgendwo auf ftp://ftp.uni-stuttgart.de gibt und das diese Problemstellung für Unix-Systeme löst.


Frage 16.6: Wie kann ein Prozeß eine Umgebungsvariable seines aufrufenden Programmes verändern?

Antwort: Im allgemeinen nicht. Verschiedene Betriebssysteme implementieren eine Funktionalität ähnlich wie bei Unix-Umgebungen. Ob eine "Umgebung" sinnvoll geändert werden kann, und wenn ja, wie, ist eine systemspezifische Frage.

Unter Unix kann ein Prozeß seine eigene Umgebung verändern (einige Systeme unterstützen hierfür die Funktionen setenv() und/oder putenv()), und die veränderte Umgebung wird gewöhnlich an alle Kind-Prozesse weitergegeben, jedoch nicht zurück an den Eltern-Prozeß.


Frage 16.7: Wie kann ich überprüfen ob eine Datei existiert? Ich möchte den Anwender fragen, bevor eine vorhandene Datei überschrieben wird.

Antwort: Unter Unix-Systemen kann man die Funktion access() verwenden, obwohl es dabei ein paar Probleme gibt (sie bildet mit der folgenden Aktion keine atomare [ununterbrechbare] Einheit und kann Anomalien zeigen, wenn sie von setuid-Programmen aufgerufen wird). Eine andere (vielleicht bessere) Möglichkeit ist es, stat() für auf diese Datei aufzurufen. Ansonsten ist der einzige, garantiert funktionierende und portable Weg, das Vorhandensein einer Datei zu überprüfen, zu versuchen diese zu öffnen (was jedoch nicht verhindert eine bestehende Datei zu öffnen, es sei denn es gibt soetwas, wie die BSD-Unix O_EXCL Option für die Funktion open()).


Frage 16.8: Wie finde ich die Größe einer Datei heraus, bevor ich diese einlese?

Antwort: Wenn mit "Größe einer Datei" die Anzahl der Bytes gemeint ist, die man unter C einlesen kann, dann ist es unmöglich, deren Anzahl im voraus festzustellen. Unter Unix gibt stat() die genaue Antwort, viele andere Systeme unterstützen Unix-ähnliche stat()-Funktionen, welche die annähernde Anzahl angeben. Man kann mit der Funktion fseek() zum Ende der Datei gehen und dann ftell() verwenden (um die absolute Position innerhalb der Datei zu bestimmen Anm. d. Übers), aber diese Methode ist nicht portabel (sie ergibt lediglich unter UNIX eine genaue Antwort und ansonsten eine quasi-genaue Antwort, die nur für binäre Dateien im Sinne von ANSI-C gültig ist). Manche Systeme unterstützen Routinen wie filesize() oder filelength().

Muß die Größe der Datei tatsächlich vorher bestimmt werden? Da der genaueste Weg, die Größe einer Datei zu bestimmen, darin besteht, diese zu öffnen und sie zu lesen, kann vielleicht der Programmcode so umgestellt werden, dass die Größe während des Lesens festgestellt wird.


Frage 16.9: Wie kann eine Datei gekürzt werden, ohne sie komplett zu löschen oder erneut zu schreiben?

Antwort: BSD-Systeme bieten ftruncate(), verschiedene andere unterstützen chsize(), und ein paar unterstützen vielleicht eine (möglicherweise undokumentierte) fcntl-Option namens F_FREESP. Unter MS-DOS kann man manchmal write(fd, "", 0) verwenden. Eine portable Lösung gibt es nicht.


Frage 16.10: Wie kann ich eine Pause (delay) oder die Messung einer Anwender-Reaktion einbauen, welche eine Auflösung im Bereich von Sekundenbruchteilen hat?

Antwort: Leider gibt es keinen portablen Weg. V7 Unix und vergleichbare System boten eine ziemlich brauchbare ftime() Funktion mit einer Auflösung bis hin zu einer Millisekunde, aber diese ist bei System V und Posix verschwunden. Andere Routinen, nach denen man suchen kann, sind nap(), setitimer(), msleep(), usleep(), clock() und gettimeofday(). Die select() und poll() Aufrufe können zweckentfremdet werden, um einfache Pausen zu erzeugen. Auf MS-DOS Maschinen ist es möglich, den System-Zeitgeber und die Timer-Interrupts neu zu programmieren.


Frage 16.11: Wie kann ich Objekt-Dateien einlesen und zu Routinen darin anspringen?

Antwort: Das wäre dann ein dynamischer Linker und/oder Lader. Es ist möglich, etwas Speicher zu belegen und dann die Objekt-Datei einzulesen, aber man muß sehr viel über die Formate von Objekt-Dateien, Relokationen usw. wissen. Unter BSD Unix kann man system() und ld -A verwenden um das Linken zu bewerkstelligen. Viele (die meisten?) Versionen von SunOS und System V haben eine -ldl Bibliothek, die das dyamische Laden von Objekt-Dateien ermöglicht. Es gibt außerdem ein GNU-Paket namens "dld". Siehe dazu die Frage 7.6


Frage 16.12: Wie kann ich innerhalb eines C-Programmes ein Kommando des Betriebssystems aufrufen?

Antwort: Durch Verwendung von system(). Da das Programm aber damit zwangsläufig Abhängigkeiten vom verwendeten Betriebssystem hat, sollte wo möglich auf C-Funktionen ausgewichen werden.

Querverweise: K&R II Sek. B6 S. 253; ANSI Sek. 4.10.4.5; H&S Sek. 21.2; PCS Sek. 11 S. 179;


Frage 16.13: Wie kann ich innerhalb eines C-Programmes ein Kommando des Betriebssystems aufrufen und dessen Ausgaben auffangen?

Antwort: Unix und einige andere Betriebssysteme unterstützen eine popen() Routine, die einen stdio Stream bildet, welcher die Ausgaben des entsprechenden Prozesses beinhaltet, so dass dessen Ausgaben gelesen werden können. Alternativ kann man den Befehl einfach so ausführen (siehe Frage 16.12), dass er seine Ausgaben in eine Datei schreibt, diese anschließend öffnet und einliest.

(Anm. d. Übers.: Bei vielen Betriebssystemen ist es erforderlich, den entsprechenden Befehl innerhalb einer Shell zu starten, da das erforderliche Pipe-ing eine Eigenschaft der Shell ist.)

Querverweise: PCS Sek. 11 S. 169.


Frage 16.14: Wie kann ich in einem C-Programm ein Verzeichnis lesen?

Antwort: Man sollte überprüfen, ob die Funktionen opendir() und readdir() benutzt werden können, die bei den meisten Unix Systemen vorhanden sind. Es gibt auch Implementationen für MS-DOS, VMS und andere Systeme (MS-DOS hat Routinen namens FINDFIRST und FINDNEXT, die im Grunde das gleiche machen.).


Frage 16.15: Wie kann ich serielle ("Comm") Ports nutzen?

Antwort: Das ist systemabhängig. Unter Unix kann man normalerweise die Gerätetreiber im Verzeichnis /dev öffnen, diese lesen und schreiben und die Möglichkeiten des Treibers nutzen, um deren Eigenschaften zu verändern. Unter MS-DOS kann man entweder einige primitive BIOS Aufrufe nutzen, oder (wenn es besonders effizient sein soll) eines von vielen Interrupt-gesteuerten seriellen I/O-Paketen nutzen.

[ Inhalt ][ Index ][ ZurÜck ][ Weiter ]


[ FAQ Logo ]   © 1997-2004 Jochen Schoof (joscho@bigfoot.de)
Diese Version wurde am 14. März 2004 erzeugt. Sie wird zukünftig nicht weiter gepflegt.