Willkommen zu »C-Programmierung für Linux in 21 Tagen«. Die heutige Lektion bildet den Einstieg für alle zukünftigen Experten auf diesem Gebiet. Heute lernen Sie:
Heutzutage steht in der Welt der Computerprogrammierung eine Vielzahl höherer Programmiersprachen zur Auswahl, zum Beispiel C, C++, Perl, Python, Tcl/Tk, BASIC und Java. Alles ohne Zweifel ausgezeichnete Programmiersprachen, die mit den meisten Programmieraufgaben spielend fertig werden. Trotzdem gibt es einige Gründe, warum professionelle Programmierer C bevorzugen:
Wie diese Punkte zeigen, ist C eine ausgezeichnete Wahl für den Programmieranfänger. Wie steht es jedoch mit C++? Vielleicht haben Sie bereits von C++ und der damit verbundenen Programmiertechnik der objektorientierten Programmierung gehört. Vielleicht fragen Sie sich, wo die Unterschiede zwischen C und C++ liegen und ob Sie nicht C++ anstelle von C lernen sollten.
Glücklicherweise brauchen Sie sich darüber nicht den Kopf zu zerbrechen. C++ ist eine Obermenge von C, womit ich sagen will, dass C++ alles von C enthält plus einigen Zusätzen für die objektorientierte Programmierung. Für jemanden, der das Programmieren erst lernen will, ist es sicherlich von Vorteil, eine kleine, relativ einfache Sprache wie C zu erlernen statt einer großen, komplexen Sprache wie C++. Wenn Sie sich anschließend dem Studium von C++ widmen, lässt sich fast alles, was Sie zu C gelernt haben, auf die Obermenge C++ übertragen. Wer C lernt, lernt nicht nur eine der mächtigsten und populärsten Programmiersprachen, sondern bereitet sich damit auch auf die objektorientierte Programmierung vor.
Eine weitere Programmiersprache, die immer mehr in den Mittelpunkt rückt, ist Java. Java basiert auf C++, das wiederum auf C basiert. Wenn Sie sich später entscheiden sollten, Java zu lernen, werden Sie feststellen, dass fast alles, was Sie zu C gelernt haben, auch für Java gilt.
Die Programmiersprache C wurde 1972 von Dennis Ritchie in den Bell Telephone Laboratories entwickelt. Das Ziel dieser Sprache war es, die Programmierung des Unix-Betriebssystems zu erleichtern und von der Assembler-Sprache wegzukommen. Außerdem wurde es dadurch wesentlich leichter, Programme zwischen Computern mit unterschiedlicher Hardware auszutauschen.
Ihre Leistungsfähigkeit und Flexibilität machte C schnell auch außerhalb der Bell- Labore bekannt. Überall begannen Programmierer damit, die verschiedensten Programme aufzusetzen. Bald jedoch entwickelten unterschiedliche Organisationen ihre eigenen C-Versionen, und die feinen Unterschiede zwischen den Implementierungen bereiteten den Programmierern nicht selten großes Kopfzerbrechen. Zur Lösung dieses Problems richtete das amerikanische Normungsinstitut (American National Standards Institute ANSI) 1983 ein Komitee ein, das eine Standarddefinition von C erarbeiten sollte, die dann als ANSI-C- Standard bekannt wurde. Etwas später, in den frühen 90ern, gab die internationale Normungsbehörde (International Standards Organization, ISO) einen neuen Standard heraus, der auch international anerkannt wurde. Mit wenigen Ausnahmen entspricht jeder moderne C-Compiler diesen Standards.
Die Programmiersprache C heißt C, da ihr Vorläufer B genannt wurde. Die Programmiersprache B wurde von Ken Thompson, ebenfalls an den Bell Laboratories, entwickelt. Es dürfte Ihnen nicht schwer fallen, zu raten, warum sie B heißt.
Programme lösen Probleme. Sie können nicht alle Probleme lösen, aber sie können computerbezogene Probleme lösen. Wenn Sie durch das World Wide Web surfen wollen, gibt es ein Programm, den so genannten Webbrowser, der dieses Problem für Sie löst. Dies ist ein konkretes Problem mit einer konkreten Lösung - einem Webbrowser. Zu anderen computerbezogenen Problemen gibt es vielleicht keine oder nicht so optimale Lösungen. Bleiben wir beim Beispiel des Webbrowsers. Vielleicht ist Ihnen zu dem Webbrowser noch ein Verbesserungsvorschlag eingefallen, den Sie gerne implementiert sähen. Damit hätten Sie ein Programmierproblem zu lösen.
Um das Programmierproblem zu lösen, sollten Sie schrittweise vorgehen. Zuerst müssen Sie das Problem definieren. Wenn Sie das Problem nicht kennen, können Sie auch keine Lösung dafür finden! Erst wenn Sie das Problem umrissen haben, können Sie überlegen, wie es zu beheben ist. Sobald Sie einen Plan haben, können Sie diesen in der Regel auch implementieren. Ist der Plan implementiert, müssen Sie die Ergebnisse überprüfen, um festzustellen, ob damit das Problem gelöst wurde. Diese Logik lässt sich auf viele Bereiche übertragen einschließlich der Programmierung.
Wenn Sie ein Programm in C (oder einer anderen Programmiersprache) erstellen, sollten Ihre Schritte ungefähr wie folgt aussehen:
Ein Beispiel für ein mögliches Ziel (siehe Schritt 1) wäre die Entwicklung eines Textverarbeitungssystems oder eines Datenbankprogramms. Eine wesentlich einfachere Zielsetzung ist es, Ihren Namen auf dem Bildschirm auszugeben. Wenn Sie keine Zielvorstellung hätten, würden Sie kein Programm schreiben, deshalb ist der erste Schritt bereits getan.
Als zweiten Schritt sollten Sie die Hilfsmittel bestimmen, die Sie für die Erstellung des Programms benötigen. Benötigen Sie zur Lösung des Problems ein Computerprogramm? Welche Informationen müssen berücksichtigt werden? Welche Formeln sollen verwendet werden? Während dieses Schrittes sollten Sie versuchen festzulegen, was Sie an Wissen benötigen und in welcher Reihenfolge die Lösung implementiert werden soll.
Lassen Sie uns ein Beispiel betrachten. Angenommen jemand bittet Sie, ein
Programm zu schreiben, das die Fläche eines Kreises ermittelt. Schritt 1 ist damit
erledigt, da Sie das Ziel vor Augen haben: die Fläche eines Kreises berechnen. Schritt
2 besteht darin, festzulegen, was Sie wissen müssen, um die Fläche zu bestimmen.
Gehen wir in diesem Beispiel davon aus, dass der Benutzer dieses Programms Ihnen
den Radius des Kreises mitteilt. Mit diesem Wissen können Sie die Formel pi*r^2
anwenden, um die Antwort zu erhalten. Damit haben Sie alles Notwendige, um mit
den Schritten 3 und 4 fortzufahren, die auch als Programmentwicklungszyklus
bezeichnet werden.
Der Zyklus der Programmentwicklung teilt sich wiederum in verschiedene Schritte auf. Der erste Schritt besteht darin, dass Sie mit einem Text-Editor eine Datei erstellen, die den Quellcode enthält. Im zweiten Schritt kompilieren Sie diesen Quellcode, um eine ausführbare Datei zu erzeugen. Als dritten Schritt führen Sie das Programm aus, um festzustellen, ob es wie geplant funktioniert.
Schritt 1 Setzen Sie Ihren Quellcode mit Hilfe eines Text-Editors auf. In der Regel haben Quellcode-Dateien in C die Extension .c
(zum Beispiel meinprog.c, datenbank.c).
Schritt 2 Kompilieren Sie das Programm mit einem Compiler. Wenn der Compiler keine Fehler feststellt, wird die Datei gelinkt und eine ausführbare Datei erstellt. Fahren Sie dann mit Schritt 3 fort. Enthält Ihr Programm Fehler, müssen Sie zurück zu Schritt 1 und diese erst beheben.
Schritt 3 Führen Sie das Programm aus. Sie sollten sich anhand von Tests vergewissern, dass das Programm erwartungsgemäß funktioniert. Wenn nicht, beginnen Sie wieder bei Schritt 1 und nehmen die entsprechenden Änderungen oder Erweiterungen an Ihrem Quelltext vor.
Abbildung 1.1 veranschaulicht die Schritte der Programmentwicklung. Normalerweise werden Sie diese Schritte mehrmals durchlaufen, bevor Sie Ihr Programm beenden, es sei denn, Sie haben ein extrem einfaches Programm; denn selbst erfahrene Programmierer können sich nicht einfach hinsetzen und ein vollständiges und absolut fehlerfreies Programm in nur einem Durchgang schreiben. Da dieser Entwicklungszyklus (Bearbeiten-Kompilieren-Linken-Testen) mehrmals durchlaufen wird, ist es wichtig, sich mit den dafür notwendigen Werkzeugen vertraut zu machen - dem Text-Editor und dem Compiler gcc.
Abbildung 1.1: Die Schritte der C-Programmentwicklung.
Um C-Programme unter Linux zu schreiben, benötigen Sie zusätzliche Programme,
die wahrscheinlich schon auf Ihrem Rechner installiert sind. Dazu gehören ein Text-
Editor, ein C-Compiler und Tools wie das make
-Programm und Debugger. Was genau
davon verfügbar ist, untersuchen wir, wenn wir die jeweiligen Tools einsetzen.
Auf vielen anderen Systemen wie Apple Macintosh und Microsoft Windows werden inzwischen so genannte integrierte Entwicklungsumgebungen (abgekürzt IDE, für Integrated Development Environment) eingesetzt, die Text-Editor, Compiler und weitere Tools in sich vereinen. Seit 1999 gibt es solche integrierten Entwicklungsumgebungen auch für Linux, doch die große Mehrheit der Linux-Programmierer verwendet weiterhin separate Tools.
Der Quellcode besteht aus einer Reihe von Anweisungen oder Befehlen, die bewirken, dass der Computer die von Ihnen gewünschten Aufgaben erledigt. Wie bereits erwähnt, besteht der erste Schritt im Zyklus der Programmentwicklung darin, den Quellcode in einen Text-Editor einzugeben. Nehmen wir zum Beispiel die folgende Zeile C-Code:
printf("Hallo, Mama!");
Diese Anweisung teilt dem Computer mit, dass er die Nachricht »Hallo, Mama!« auf dem Bildschirm anzeigen soll. (Wie diese Anweisung genau funktioniert, soll uns im Moment nicht interessieren.)
Für die Erstellung der Quelltextdateien ist ein einfacher Text-Editor größeren Textverarbeitungssystemen stets vorzuziehen. Die meisten Textverarbeitungssysteme verwenden speziellen Formatierungscode, der in dem Dokument mit abgespeichert wird. Dieser zusätzliche Code macht Textverarbeitungssysteme ungeeignet für die Erstellung von Programmquelltexten. Der ASCII-Code (American Standard Code for Information Interchange) definiert ein Standardtextformat, das von fast jedem Programm, einschließlich dem C-Compiler, verstanden wird.
Wenn Sie eine Quelltextdatei abspeichern, müssen Sie ihr einen Namen geben. Der
Name sollte darauf verweisen, was das Programm macht. Außerdem sollten die
Quelltextdateien Ihres C-Programms die Extension .c
erhalten. Sie können zwar Ihren
Quelltextdateien beliebige Namen und Extensionen geben, aber .c
ist die
anerkanntermaßen korrekte Extension.
Für Linux stehen viele Text-Editoren zur Verfügung, unter anderem vi, emacs, joe, ed, vim, crisp und jed. Einige dieser Editoren können von der Konsole aus ausgeführt werden (der schwarzweiße Bildschirm, den Sie sehen, wenn Linux startet und bevor die grafische Benutzerschnittstelle erscheint), andere wiederum bedürfen der grafischen Benutzerschnittstelle X Window. Zu den empfehlenswertesten Editoren mit ausschließlich grafischer Benutzeroberfläche gehören nedit, gnp und kedit. Die Nutzung dieser Text-Editoren sollte allen, die bereits einmal mit einem Textverarbeitungssystem gearbeitet haben, nicht allzu schwer fallen. In Abbildung 1.2 werden diese drei Editoren gemeinsam auf einem Bildschirm angezeigt.
Folgendermaßen können Sie herausfinden, ob einer dieser Editoren auf Ihrem Rechner vorhanden ist: Tippen Sie den jeweiligen Namen gefolgt von dem Ampersand-Zeichen (&) in die Befehlszeile ein. Das & erhalten Sie, indem Sie die Umschalttaste zusammen mit der Taste 6 drücken. Auf diese Weise wird der Editor im Hintergrund ausgeführt und Sie können weiterhin Befehle auf der Konsole eingeben.
Alternative Text-Editoren für Linux suchen Sie am besten auf einer der vielen Web-Sites im Internet, die Linux-Programme zum Herunterladen auflisten, oder Sie bedienen sich einer Internet-Suchmaschine. Am geschicktesten ist es jedoch, wenn Sie gleich zu der Web-Site der von Ihnen verwendeten Linux-Version gehen.
Auch wenn Sie vielleicht in der Lage sind, C-Code zu verstehen (spätestens nach dem Studium dieses Buches werden Sie dazu in der Lage sein) - Ihr Computer versteht den Code nicht. Ein Computer benötigt digitale beziehungsweise binäre Anweisungen in der so genannten Maschinensprache. Bevor Ihr C-Programm auf einem Rechner ausgeführt werden kann, muss der Quellcode in die Maschinensprache übersetzt werden. Diese Übersetzung, der zweite Schritt in der Programmentwicklung, wird von einem so genannten Compiler-Programm erledigt. Der Compiler erhält Ihren Quelltext als Eingabe und erzeugt daraus eine Datei, in der die Anweisungen des Quellcodes in Maschinensprache vorliegen.
Der bekannteste C-Compiler unter Linux ist der GNU-C-Compiler namens gcc.
Um festzustellen, ob der C-Compiler bereits installiert ist, geben Sie den Befehl
gcc -v
in die Befehlszeile ein. Ist er installiert, erhalten Sie eine Nachricht, die ungefähr der Nachricht auf der Konsole in Abbildung 1.3 entspricht. Und zerbrechen Sie sich nicht den Kopf, wenn Ihre Nachricht nicht mit der abgebildeten Meldung identisch ist. Dann haben Sie wahrscheinlich eine etwas andere C-Compiler-Version. Wenn die Nachricht jedoch besagt, dass der Befehl nicht gefunden wurde, sollten Sie das Handbuch zu Ihrer Linux-Version zu Rate ziehen und herausfinden, wie man den C-Compiler installiert. Dabei ist es ratsam, bei der Installation des C-Compilers die anderen Entwicklungs-Tools gleich mitzuinstallieren.
Abbildung 1.3: Eine typische Red Hat 6.1 Installation mit einer Konsole, die die Ergebnisse der Befehle gcc -v und make -v zeigt.
Der Compiler gcc
wird von der Befehlszeile ausgeführt. Vorausgesetzt die
Quelltextdatei radius.c befindet sich im aktuellen Verzeichnis, lautet der Befehl zur
Kompilierung und Erzeugung einer ausführbaren Datei:
gcc radius.c
Damit erzeugen Sie in dem aktuellen Verzeichnis eine Ausgabedatei, die traditionell
a.out
heißt. Um selbst einen Dateinamen für die Ausgabedatei vorzugeben, müssen
Sie gcc
wie folgt aufrufen:
gcc radius.c -o radius
Dieser Befehl weist gcc
an, eine Quelltextdatei namens radius.c
zu kompilieren und
eine Ausgabedatei namens radius
zu erzeugen. Diese Ausgabedatei (die auch einen
gänzlich anderen Namen erhalten könnte) ist eine ausführbare Datei, sprich ein
Programm, das auf Ihrem Computer ausgeführt werden kann. Um das Programm
auszuführen, geben Sie bei dem Befehlszeilen-Prompt den Befehl ./radius
ein. Der
Punkt und der Schrägstrich signalisieren dem Befehls-Interpreter auf der Konsole, das
Programm namens radius
im aktuellen Verzeichnis zu suchen. Ohne ./
würde der
Befehls-Interpreter in dem so genannten aktuellen Pfad danach suchen (führen Sie
den Befehl echo $PATH
aus, um sich den aktuellen Pfad anzuschauen).
Der C-Compiler kann jedoch nicht nur Ihren C-Quellcode in eine ausführbare Datei
kompilieren, sondern Ihnen auch mitteilen, wo Fehler bei der Kompilierung
aufgetreten sind. Dabei wäre es jedoch wenig sinnvoll, wenn der Compiler lediglich
die Fehler im Quelltext registrierte, ohne Ihnen anzuzeigen, wo und wieso die Fehler
aufgetreten sind. Der C-Compiler kann außerdem Warnungen ausgeben, wenn er auf
Code trifft, den er zwar übersetzen kann, der aber vermutlich zu einem Fehler im
Programm führt. Verständlicherweise möchten Sie als Programmierer so viele
Informationen wie möglich über potentielle Fehler in Ihrem Programm. Deshalb ist es
sinnvoll, den Compiler so einzustellen, dass er möglichst viele Warnungen erzeugt.
Wenn Sie Ihr Programm darüber hinaus mit dem ddd
-Debugger kontrollieren wollen,
müssen Sie den Compiler anweisen, zusätzliche, vom Debugger benötigte
Informationen in die ausführbare Datei mit aufzunehmen. Der Aufruf von gcc
, der alle
Warnungen einschaltet und Debug-Informationen hinzufügt, lautet:
gcc -Wall -ggdb radius.c -o radius
Die Direktive -Wall
teilt gcc
mit, alle möglichen Warnungen auszugeben, während
-ggdb
dazu dient, die Debug-Informationen für den gdb
-Debugger, der von ddd
verwendet wird, hinzuzufügen. Auf diese Weise werden Sie die meisten Programme in
diesem Buch kompilieren. Am Tag 20, »Compiler für Fortgeschrittene«, werden wir
uns dem Thema zuwenden, wie man Programme schreibt und kompiliert, die aus
mehreren C-Quelltextdateien bestehen. Aber erst einmal sind unsere Programme alle
in einer einzigen Quelltextdatei untergebracht.
Nachdem Ihr Programm kompiliert ist und eine ausführbare Datei erzeugt wurde,
können Sie es ausführen, indem Sie den Namen auf der Konsole eingeben. Denken
Sie jedoch daran, vor den Namen ./
zu setzen. Wenn Sie nach Ausführung des
Programms Ergebnisse erzielen, die nicht Ihren Erwartungen entsprechen, müssen
Sie zurück zu Schritt 1. Stellen Sie fest, wo der Fehler liegt, und ändern Sie dann den
Quelltext entsprechend. Alle Änderungen am Quelltext machen eine erneute
Kompilierung des Programms erforderlich, um eine korrigierte Version der
ausführbaren Datei zu erhalten. Dieser Zyklus wird so lange durchlaufen, bis Ihr
Programm genau das macht, wofür es geschrieben wurde.
Auch als Neuling in der Programmentwicklung werden Sie bald feststellen, dass
Programme bei ihrer ersten Ausführung selten das tun, was sie sollen. Zum Auffinden
und Beheben von Fehlern in einem Programm gibt es ein spezielles, häufig
eingesetztes Programmierwerkzeug, den so genannten Debugger. Ein Debugger ist
ein Programm, das es dem Programmierer erlaubt, sein Programm auf der Suche
nach potentiellen Fehlern Zeile für Zeile durchzugehen. Abbildung 1.4 zeigt Ihnen
den ddd
-Debugger, der eine grafische Benutzeroberfläche aufweist. Ich möchte Ihnen
nahe legen, dieses Programm das ganze Buch hindurch einzusetzen. Verwenden Sie
es nicht nur zum Debuggen, sondern auch zum Lernen. Verwenden Sie es, um Ihre
Programme schrittweise durchzugehen und Einsicht in die Funktionsweise Ihrer
Programme zu bekommen. Etwas weiter hinten, im Abschnitt »Der ddd-Debugger«,
beschreibe ich kurz, wie Sie ddd
nutzen können, um ein einfaches Programm
zeilenweise zu durchlaufen.
Abbildung 1.4: Der ddd-Debugger. Er weist zwei Fenster auf: ein Hauptfenster, in dem der Code angezeigt wird, und ein zweites kleineres Fenster mit Steuerschaltflächen (rechts).
Es gibt noch ein weiteres wichtiges Programmierwerkzeug, das vorhanden sein sollte:
das make
-Programm. Nach der Eingabe von make -v
in der Befehlszeile sollte eine
Nachricht wie in Abbildung 1.3 erscheinen, auch wenn Sie nicht absolut identisch sein
muss. Mit dem make
-Programm beschäftigen wir uns erst am Tag 20, wenn wir auf die
Kompilierung von Mehrdateienprogrammen zu sprechen kommen.
Das letzte Programm, das Sie noch benötigen, dient dazu, die Programmierer-
Dokumentation Ihres Linux-Systems einzusehen. Außer den üblichen Manpages (siehe
Abschnitt 1.4) gibt noch eine Unmenge von nützlichen Informationen, die im GNU-
Format verfügbar sind. Sie können diese Informationen mit Hilfe des Programms info
anzeigen lassen. Geben Sie info
im Konsolenfenster ein und Sie erhalten einen
einführenden Bildschirm zu dem Informationssystem (drücken Sie q
für »quit«, wenn
Sie das Programm wieder verlassen wollen). Leider ist das Programm info
nicht
sonderlich benutzerfreundlich, aber viele Linux-Systeme verfügen über eigene
Dokumentations-Leseprogramme wie kdehelp
oder gnome-help-browser
. Um
festzustellen, ob eines dieser Programme auf Ihrem System installiert ist, brauchen Sie
nur den Namen auf der Befehlszeile Ihrer Konsole eintippen. Ist eines der Programme
verfügbar, versuchen Sie die Informationsseiten »System GNU Info Contents« unter
kdehelp
und »Info Pages« unter gnome-help-browser
zu finden. Zu Ihrer Information:
Beide Systeme können auch dazu benutzt werden, die Manpages einzusehen.
Setzen wir in diesem Buch einfach mal voraus, dass Linux auf Ihrem System bereits läuft und dass Sie schon das Vorhandensein der erforderlichen Werkzeuge überprüft haben. Gehen wir weiter davon aus, dass Sie über die grafische X Window- Benutzerschnittstelle verfügen. Sollte diese Schnittstelle noch fehlen, installieren Sie sie mit Hilfe der Dokumentation zu Ihrer Linux-Version.
Sobald Sie soweit sind, sich in Ihr System einzuloggen, sollten Sie ein Konsolenfenster aufrufen (siehe Abbildung 1.3). Unter der Standardinstallation von Red Hat Linux 6.0/6.1 heißt das Fenster »Terminal«, unter anderen Linux-Distributionen läuft das Konsolenfenster unter der Bezeichnung xterm, kconsole oder Konsole.
Falls Sie derzeit als
root
-Anwender, das heißt als Systemadministrator, auf Ihrem Linux-System gemeldet sind, sollten Sie ein Benutzerkonto ohne Privilegien einrichten und dieses für Ihr Studium von C verwenden. Das Konto desroot
-Anwenders hat uneingeschränkten Zugriff auf die Maschine und kann deshalb grenzenlosen Schaden anrichten, wenn ein Programm aus dem Ruder läuft. Als Benutzer ohne Privilegien auf einem korrekt eingerichteten Linux-Rechner können Sie schlimmstenfalls Ihre eigenen Dateien beschädigen. Es ist äußerst unwahrscheinlich, dass Sie Dateien beschädigen, die zum Betriebssystem gehören oder von diesem benötigt werden.
Wenn das Konsolenfenster angezeigt wird, sollten Sie eine Reihe der geläufigsten
Befehle ausprobieren, wie zum Beispiel ls
(Verzeichnis auflisten), pwd
(Arbeitsverzeichnis ausgeben), ps
(Prozesse auflisten), mkdir
(Verzeichnis anlegen) und
cd
(Verzeichnis wechseln). Alle Befehle in Linux unterscheiden zwischen Groß- und
Kleinschreibung. Der Befehl LS
(wenn es ihn gäbe) entspricht nicht dem Befehl ls
.
Weitere Informationen zu diesen Programmen können Sie den Manpages entnehmen
(mit Hilfe des Befehls man
). Der Aufruf von man ls
zum Beispiel wird Ihnen alles
Wissenswerte zu dem Befehl ls
liefern. Wenn Sie die Manpage verlassen wollen,
drücken Sie die Taste q
, um zur Befehlszeile zurückzukehren. Die meisten Linux-
Versionen enthalten Manpages zu fast allen Programmen und
Betriebssystemeigenschaften.
Die Konsole besteht eigentlich aus zwei Programmen: eines für das Fenster selbst und ein zweites, den so genannten Befehlsinterpreter, der, wie der Name schon verrät, die vom Benutzer eingegebenen Befehle interpretiert und ausführt. Der am weitesten verbreitete Befehlsinterpreter unter Linux heißt GNU
bash
(Bourne Again SHell), obwohl auch viele andere zur Verfügung stehen.
Der größte Teil der Programme in diesem Buch, die Sie zum Üben der C- Programmierung schreiben, werden von der Befehlszeile einer Konsole ausgeführt.
Wahrscheinlich warten Sie schon gespannt darauf, Ihr erstes Programm in C zu schreiben. Damit Sie mit Ihrem Compiler schnell vertraut werden, finden Sie in Listing 1.1 ein kurzes Programm, anhand dessen wir den Zyklus der Programmerstellung durchexerzieren werden. Wahrscheinlich werden Sie im Moment noch nicht alles verstehen, aber Sie erhalten zumindest ein Gefühl für den Ablauf des Entwicklungszyklus: Schreiben, Kompilieren und Ausführen eines richtigen C- Programms.
Bei diesem Beispiel handelt es sich um ein Programm namens hallo.c
, das nichts
anderes macht, als die Worte »Hallo, Welt!« auf dem Bildschirm auszugeben. Dieses
Programm, mit dem traditionell in die C-Programmierung eingeführt wird, ist ein
gutes Lernbeispiel. Der Quellcode für hallo.c
befindet sich in Listing 1.1. Wenn Sie
dieses Listing abtippen, müssen Sie die Zeilennummerierung und die Doppelpunkte
zur Linken fortlassen.
1: #include <stdio.h>
2:
3: int main(void)
4: {
5: printf("Hallo, Welt!\n\n");
6: return 0;
7: }
Stellen Sie sicher, dass, wie bereits vorher beschrieben, gcc
auf Ihrem Rechner
installiert ist und ordnungsgemäß funktioniert und dass Sie über einen geeigneten
Text-Editor verfügen. Sind Compiler und Editor bereit, dann folgen Sie den
nachstehenden Schritten, um hallo.c
einzugeben, zu kompilieren und auszuführen.
Gehen Sie beim Eingeben und Kompilieren des Programms hallo.c
wie folgt vor:
hallo.c
genauso ein wie in
Listing 1.1. Drücken Sie nach jeder Zeile die Eingabetaste.
Lassen Sie die Zeilennummern und Doppelpunkte fort. Sie dienen lediglich dazu, in diesem Buch den Verweis auf bestimmte Quelltextzeilen zu vereinfachen.
hallo.c
.
hallo.c
sich auf Ihrer Festplatte befindet, indem Sie die Liste
der Dateien in dem Verzeichnis mit dem Befehl ls
im Konsolenfenster anzeigen
lassen. Unter den angezeigten Dateien sollte auch hallo.c
zu finden sein.
hallo.c
mit dem folgenden Befehl im Konsolenfenster zu einem
richtigen Programm.
gcc -Wall -ggdb hallo.c -o hallo
printf
das Wort prntf
eingegeben hätten, würden Sie ungefähr
folgende Meldung erhalten:
hallo.c: In function `main':
hallo.c:5: warning: implicit declaration of function `prntf'
/tmp/cco48R7q.o: In function `main':
/home/erikd/hello/hallo.c:5: undefined reference to `prntf'
collect2: ld returned 1 exit status
hallo.c
in Ihrem Editor. Vergleichen
Sie den Inhalt Ihrer Datei noch einmal sorgfältig mit Listing 1.1. Nehmen Sie alle
notwendigen Korrekturen vor und fahren Sie dann mit Schritt 3 fort.
hallo
(und einer beliebigen
Extension) auflisten, sollten Sie folgendes Ergebnis erhalten:
hallo.c
- die Quelltext-Datei, die Sie mit Ihrem Editor erstellt haben
hallo
- d
as beim Kompilieren und Linken von hallo.c
erzeugte ausführbare
Programm
hallo
auszuführen, müssen Sie lediglich ./hallo
eingeben. Damit wird die
Meldung »Hallo, Welt!« auf dem Bildschirm ausgegeben.
Meinen Glückwunsch! Sie haben gerade Ihr erstes C-Programm eingegeben,
kompiliert und ausgeführt. Zugegeben, hallo.c
ist ein einfaches Programm, das
eigentlich nichts besonders Nützliches macht, aber es ist immerhin ein Anfang. Und
um ehrlich zu sein, die meisten der heutigen C-Experten haben C auf genau dem
gleichen Weg gelernt - durch das Kompilieren von hallo.c
. Sie befinden sich also in
bester Gesellschaft.
Ein Kompilierfehler tritt auf, wenn der Compiler irgendetwas im Quellcode findet, das er nicht kompilieren kann. Fehlerhafte Schreibweise, typografische Fehler oder ein Dutzend anderer Dinge können beim Compiler einen Fehler auslösen. Zum Glück jedoch brechen moderne Compiler den Kompiliervorgang nicht ab, ohne Ihnen mitzuteilen, warum sie versagt haben und wo das Problem liegt. Damit haben Sie es wesentlich leichter, Fehler in Ihrem Quelltext aufzuspüren und zu korrigieren.
Um Ihnen dies einmal zu veranschaulichen, wurde in dem Programm hallo.c
von
oben absichtlich ein Fehler eingefügt. Wenn Sie das Beispiel durchgearbeitet haben
(und das sollten Sie), haben Sie inzwischen eine Kopie von hallo.c
auf Ihrer
Festplatte. Rufen Sie Ihren Editor auf und setzen Sie den Cursor an das Ende der Zeile
mit dem Aufruf von printf()
. Entfernen Sie dort das abschließende Semikolon.
Danach sollte hallo.c
wie in Listing 1.2 aussehen.
Listing 1.2: hallo.c mit einem Fehler.
1: #include <stdio.h>
2:
3: int main(void)
4: {
5: printf("Hallo, Welt!\n\n")
6: return 0;
7: }
Sichern Sie danach die Datei. Jetzt können Sie sie erneut kompilieren. Geben Sie dazu den entsprechenden Befehl an den Compiler ein. Wegen des Fehlers wird die Kompilierung nicht abgeschlossen. Statt dessen zeigt Ihnen der Compiler in etwa folgende Meldung an:
hallo.c: In function `main':
hallo.c:6: parse error before `return'
hallo.c:7: warning: control reaches end of non-void function
Der kleine, von Ihnen eingebaute Fehler hat drei Compiler-Meldungen ausgelöst. Jede Meldung gibt am Zeilenanfang den Namen der C-Quelltextdatei an, die zweite und dritte Meldung schließt daran sogar noch die Nummer der Zeile an, in der der Fehler festgestellt wurde. Beachten Sie, dass es sich bei der dritten Meldung um eine Warnung handelt.
Die Meldungen sind recht informativ. Sie teilen Ihnen mit, dass in der Funktion `main
'
etwas falsch gelaufen und in Zeile 6 vor `return
' ein Fehler aufgetreten ist. Warum,
werden Sie sich fragen, stellt der Compiler einen Fehler in Zeile 6 fest, wo wir doch
das Semikolon vom Ende der Zeile 5 entfernt haben? Die Antwort lautet, dass C so
etwas wie Zeilenumbrüche nicht registriert. Das Semikolon, das hinter die printf()
-
Anweisung gehört, hätte genauso gut auch in die nächste Zeile gesetzt werden
können (auch wenn dies nicht unbedingt der gängigen Programmierpraxis entspricht).
Erst wenn der Compiler auf den nächsten Befehl (return
) in Zeile 6 trifft, weiß er, dass
das Semikolon fehlt. Deshalb befindet sich für den Compiler der Fehler in Zeile 6.
Außerdem sollten Sie sich merken, dass ein Fehler in einem Teil des Programms (Zeile 6) manchmal weiter hinten im Programm (Zeile 7) einen weiteren Fehler bewirken kann. Daraus können Sie Folgendes lernen: Wenn der Compiler mehrere Fehler auflistet und Sie nur einen finden können, sollten Sie diesen Fehler erst einmal beheben und das Programm dann erneut kompilieren. Vielleicht haben Sie damit bereits alle anderen Fehler mitbeseitigt und können das Programm ohne weitere Fehlermeldungen kompilieren.
Damit dürfte ein Punkt bezüglich des C-Compilers und seiner Fehlermeldungen absolut klar geworden sein. Ein Compiler mag zwar so intelligent sein, Fehler festzustellen und zu lokalisieren, aber er ist kein Einstein. Mit Ihrem Wissen der Programmiersprache C müssen Sie die Fehlermeldungen des Compilers interpretieren und die eigentliche Position der angemerkten Fehler feststellen. Meistens befinden sich die Fehler in der von dem Compiler angegebenen Zeile und wenn nicht, sind sie fast immer in der vorangehenden Zeile zu finden. Sie werden am Anfang sicher etwas Probleme haben, die Fehler aufzuspüren, aber das wird sich schon bald legen.
In dem Abschnitt zum C-Entwicklungszyklus bestand der vierte Schritt darin, das
Programm auszuführen, um festzustellen, ob es korrekt läuft. Es ist ohne weiteres
möglich, ein C-Programm zu schreiben, das sich problemlos kompilieren lässt, aber
dennoch nicht den Zielvorstellungen entspricht. In diesem Fall sprechen wir von
einem logischen Fehler im Vergleich zu den Kompilierfehlern, die wir im
vorangehenden Abschnitt besprochen haben. Logische Fehler in großen Programmen
aufzuspüren, ist wesentlich schwieriger als Kompilierfehler festzustellen. Hier ist uns
der Debugger eine wertvolle Hilfe, denn er ermöglicht es uns, ein Programm
zeilenweise durchzugehen. Auf diese Art und Weise können Sie den Programmablauf
Zeile für Zeile verfolgen und prüfen, ob das Programm auch so arbeitet, wie Sie es
beim Schreiben des Programms beabsichtigt hatten. In diesem Buch werden wir den
ddd
-Debugger weniger zum Debuggen, sondern vielmehr als Lernhilfe verwenden.
Bevor Sie den ddd
-Debugger einsetzen können, müssen Sie ihn erst einmal korrekt
einrichten. Angenommen Sie haben ddd
bereits zur Verfügung, dann starten Sie ihn
vom Konsolenfenster mit der Eingabe von ddd
. Wenn Sie ddd
zum ersten Mal nutzen,
müssen Sie sich durch ein oder zwei Start-Bildschirme durchklicken, bis Sie zum
Hauptfenster kommen. Klicken Sie dann in der Menüleiste auf Edit (Bearbeiten) und
wählen Sie aus dem zugehörigen Menü den Punkt GDB Settings (GDB-Einstellungen)
aus. Sie gelangen dann in ein Dialogfeld mit einer Bildlaufleiste zur Rechten. Scrollen
Sie mit dieser Bildlaufleiste bis ungefähr zur Mitte, bis Sie zu dem Punkt Autoloading
of Shared Library Symbols (Gemeinsame Bibliothekssymbole automatisch laden)
kommen. Entfernen Sie dann, wie in Abbildung 1.5 zu sehen, durch Klicken die
Markierung aus dem Kästchen links von diesem Punkt, so dass die Option
ausgeschaltet ist. Um Ihre Änderungen zu sichern, müssen Sie im Dialogfeld den OK-
Schalter anklicken und dann im Menü Edit (Bearbeiten) auf Save Options (Optionen
sichern) klicken.
Jetzt können Sie damit beginnen, mit ddd
ein Programm zu debuggen. Setzen Sie in
Ihrem Editor den Quelltext zu dem nachfolgenden Programm auf (Listing 1.3) und
kompilieren Sie es. Denken Sie daran, gcc
mitzuteilen, die Debug-Informationen, die
vom Debugger benötigt werden, hinzuzufügen. Das ausführbare Programm sollte den
Namen hallo2
erhalten.
Listing 1.3: hallo2.c, ein Programm zum Experimentieren mit dem Debugger.
1 : #include <stdio.h>
2 :
3 : int main(void)
4 : { int count ;
5 :
6 : printf ("Hallo!!!\n") ;
7 :
8 : printf ("Start ... \n") ;
9 : for (count = 0 ; count < 5 ; count++)
10: printf ("Zaehler = %d\n", count) ;
11:
12: printf ("fertig.\n\n") ;
13:
14: return 0 ;
15: }
Nachdem das Programm ordnungsgemäß kompiliert und ausgeführt wurde, können Sie den Debugger einsetzen. Um den Debugger für dieses Programm aufzurufen, geben Sie nach dem Befehlsprompt des Konsolenfensters
ddd hallo2
ein. Daraufhin sollten Sie die zwei Fenster des ddd
-Debuggers und ein Dialogfeld mit
Tipps zur Arbeit mit ddd
erscheinen (das Dialogfeld können Sie gleich schließen). Das
Hauptfenster sollte den Quelltext zu hallo2.c
enthalten.
Der erste Schritt bei der Arbeit mit ddd
besteht darin, einen ersten Haltepunkt zu
setzen, an dem der Debugger nach der Initialisierung anhalten soll. Klicken Sie dazu
im Hauptfenster ganz links neben die erste Zeile, die eine »printf
«-Anweisung (Zeile
6) enthält, und anschließend in der Symbolleiste auf den »break«-Schalter (Schalter
mit dem Stoppzeichen darüber). In der Zeile mit dem printf
-Befehl sollte daraufhin
ein Stoppzeichen angezeigt werden. Jetzt können Sie den Schalter Run (Ausführen)
auf der frei beweglichen Schalterleiste anklicken, woraufhin ein grüner Pfeil neben
dem Stoppzeichen erscheint. Wenn Sie jetzt in der Schalterleiste auf den Schalter
Step (Schritt) klicken, können Sie den Code zeilenweise durchgehen. Die Ausgabe,
die von jeder Codezeile erzeugt wird, erscheint im unteren Teil des Hauptfensters. Es
leuchtet ein, dass der Debugger nicht über das Ende des Programms hinaus gehen
kann, aber Sie können jederzeit den Debugger das Programm von vorne durchgehen
lassen, indem Sie auf den Run-Schalter klicken.
Scheuen Sie sich nicht, mit dem Debugger die Beispielprogramme in diesem Buch durchzugehen. Die Arbeit mit dem Debugger wird Ihnen einen viel besseren Einblick in das Zusammenspiel zwischen der Programmiersprache C und der Arbeitsweise Ihres Rechners geben.
Nachdem Sie diese Lektion gelesen haben, sollten Sie davon überzeugt sein, dass Sie mit C als Programmiersprache für Linux eine weise Entscheidung getroffen haben. C kombiniert auf unübertroffene Weise Power, Popularität und Portabilität. Diese Faktoren, zusammen mit der engen Verwandtschaft zu objektorientierten Sprachen wie C++ oder Java, machen C fast unschlagbar.
In dieser Lektion haben Sie die verschiedenen Schritte bei der Erstellung eines C- Programms kennen gelernt - einen Prozess, den man auch Programmentwicklung nennt. Ihnen sollten jetzt sowohl der Zyklus Bearbeiten-Kompilieren-Testen als auch die für jeden Schritt erforderlichen Werkzeuge vertraut sein.
Fehler sind unvermeidbarer Bestandteil der Programmentwicklung. Ihr C-Compiler kann diese Fehler in Ihrem Quelltext aufspüren und eine entsprechende Fehlermeldung ausgeben, die Ihnen mitteilt, welcher Art der Fehler und wo er zu finden ist. Mit diesen Informationen können Sie Ihren Quelltext erneut bearbeiten und den Fehler beheben. Denken Sie jedoch daran, dass der Compiler nicht immer mit 100-prozentiger Sicherheit die Art und Position des Fehlers feststellen kann. Manchmal müssen Sie Ihre Kenntnisse in C zur Hilfe nehmen, um herauszufinden, was genau eine Fehlermeldung ausgelöst hat.
Frage:
Wenn ich zur Eingabe meines Quellcodes einen Text-Editor verwendet habe, der
mir eigentlich nicht gefällt, kann ich dann zu einem anderen wechseln, ohne den
bisher aufgesetzten Code erneut einzugeben? Sind alle Text-Editoren miteinander
kompatibel?
Antwort:
Ja, alle Text-Editoren sind kompatibel. Wenn Sie einen Text-Editor und kein
Textverarbeitungsprogramm verwenden, enthalten die von Ihnen erzeugten
Dateien nur ASCII-Zeichen. Der Wechsel zu einem anderen Text-Editor sollte
also keine Schwierigkeit darstellen, auch wenn einige Editoren unter
Umständen das [ÿ]-Zeichen etwas anders darstellen und es mit vier
Leerzeichen gleichsetzen anstatt wie normalerweise mit acht.
Frage:
Wenn ich ein von mir geschriebenes Programm jemand anderem zur Verfügung
stellen will, welche Dateien muss ich ihm dann mitgeben?
Antwort:
Einer der Vorteile von C ist, dass es sich um eine kompilierte Sprache
handelt. Das bedeutet, dass Sie nach der Kompilierung des Quellcodes ein
ausführbares Programm erhalten. Dieses ausführbare Programm ist
unabhängig. Wenn Sie also all Ihren Freunden, die unter Linux arbeiten,
hallo
geben wollen, steht dem nichts im Wege. Sie müssen Ihnen nur das
ausführbare Programm hallo
mitgeben.
Wenn Sie jedoch dieser Person die Möglichkeit zugestehen wollen, das Programm seinen eigenen Bedürfnissen oder seinem Rechner anzupassen, müssen Sie ihm den C-Quellcode zur Verfügung stellen. Dieser Quellcode muss dann jedoch erst kompiliert werden, bevor er auf dem neuen Rechner läuft. Geben Sie, wenn nötig, auch Anweisungen mit, wie Ihr Programm zu kompilieren ist.
Frage:
Muss ich die Quelltextdatei (.c) behalten, nachdem ich eine ausführbare Datei
erstellt habe?
Antwort:
Wenn Sie die Quelltextdatei löschen, nehmen Sie sich die Möglichkeit,
Änderungen an dem Programm vorzunehmen. Deshalb sollten Sie diese Datei
behalten. Solange Sie über die Quelltextdatei (.c) verfügen, können Sie
jederzeit die anderen Dateien neu erstellen.
Frage:
Kann ich die Fehlermeldungen ignorieren?
Antwort:
Einige Warnungen beeinflussen die Ausführung des Programms und andere
nicht. Wenn der Compiler eine Warnung ausgibt, sollte dies für Sie ein Signal
sein, dass irgendetwas nicht in Ordnung ist. Sie sollten jede Warnung
analysieren und eine Entscheidung fällen. Am besten ist es, wenn Sie Ihre
Programme so schreiben, dass sie absolut keine Warnungen oder Fehler
enthalten. (Wenn ein Fehler auftritt, erzeugt der Compiler keine ausführbare
Datei.)
Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, sowie Übungen, die Sie anregen sollen, das Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Die Lösungen zu den Fragen und den Übungen finden Sie in Anhang C.
gcc
ein Programm namens
meinprog
aus einer C-Quelltextdatei namens programm1.c
zu erstellen?
dateiname.txt
ein gültiger Name für eine C-Quelltextdatei?
1: #include <stdio.h>
2:
3: int radius, flaeche;
4:
5: int main(void)
6: {
7: printf( "Geben Sie einen Radius ein (z.B. 10): " );
8: scanf( "%d", &radius );
9: flaeche = (int) (3.14159 * radius * radius);
10: printf( "\n\nFläche = %d\n", flaeche );
11: return 0;
12: }
1: #include <stdio.h>
2:
3: int x,y;
4:
5: int main(void)
6: {
7: for ( x = 0; x < 10; x++, printf( "\n" ) )
8: for ( y = 0; y < 10; y++ )
9: printf( "X" );
10:
11: return 0;
12: }
1: #include <stdio.h>
2:
3: int main(void);
4: {
5: printf( "Weitersuchen!" );
6: printf( "Du wirst\'s finden!\n" );
7: return 0;
8: }
1: #include <stdio.h>
2:
3: int main(void)
4: {
5: printf( "Dies ist ein Programm mit einem " );
6: tue_es( "Problem!");
7: return 0;
8: }
9: printf( "%c", 1 );