MINT lernen

Textaufgaben: Vom Quelltext zum Programm

Lena bringt ihre erste Info-Tag-Anzeige zum Laufen, und Tim jagt in den Öffnungszeiten der Bibliothek Fehlern hinterher, die C und Python ganz unterschiedlich melden.

Dein Fortschritt:
0 / 0 Aufgaben
1

Die Anzeige für den Info-Tag

AFB I–II

Lena aus der Robotik-AG soll für den Tag der offenen Tür eine kleine Begrüßungsanzeige programmieren, die auf einem Bildschirm im Flur läuft. Sie hat bisher nur in Python programmiert und schreibt nun ihr erstes C-Programm. Die Datei heißt infotag.c.

C · infotag.c
#include <stdio.h>

/* Anzeige für den Tag der offenen Tür */
int main(void) {
    printf("Willkommen im Informatikraum!\n");
    printf("Raum 204: Robotik-AG\n");    // Raum und AG
    printf("Beginn: 10 Uhr\n");
    return 0;
}

Im Terminal tippt sie gcc -Wall infotag.c -o infotag und danach ./infotag. Am Vormittag erfährt sie, dass die AG schon um 9 Uhr beginnt. Sie ändert im Editor die Zahl 10 in 9, speichert die Datei und startet sofort wieder mit ./infotag — auf dem Bildschirm steht aber weiterhin „Beginn: 10 Uhr“.

  1. Geben Sie für die Zeile #include <stdio.h>, den Kommentar, die Zeile int main(void) { und die Anweisung return 0; jeweils an, wozu sie im Programm dient.
  2. Beschreiben Sie, was nacheinander passiert, wenn Lena gcc -Wall infotag.c -o infotag eingibt. Gehen Sie dabei auf die drei Stationen der Übersetzung und auf die Bedeutung von -Wall und -o infotag ein.
  3. Erklären Sie, warum nach der Änderung weiterhin „Beginn: 10 Uhr“ erscheint, und geben Sie die Befehle in der richtigen Reihenfolge wieder, mit denen Lena die neue Uhrzeit anzeigen kann.

Hinweise

Hinweis zu Aufgabe a)
Stellen Sie sich zu jeder Zeile die Frage: Was würde fehlen, wenn sie gelöscht wäre? Eine Zeile wird vom Compiler gar nicht beachtet.
Hinweis zu Aufgabe b)
Die drei Stationen heißen Präprozessor, Compiler und Linker. Überlegen Sie, was jede davon mit der Datei macht und welche Datei am Ende auf der Festplatte liegt.„Beschreiben“ heißt hier: die Schritte in der richtigen Reihenfolge und mit Fachbegriffen wiedergeben — ohne sie zu bewerten.
Hinweis zu Aufgabe c)
Womit startet ./infotag — mit dem Quelltext oder mit einer anderen Datei? Wann wurde diese Datei zuletzt erzeugt? Denken Sie an den Unterschied zu Python.

Erwartungshorizont

Erwartungshorizont zu Aufgabe a)

#include <stdio.h>: bindet die Bibliothek für Ein- und Ausgabe ein; ohne sie kennt der Compiler printf nicht.

Kommentar /* … */ bzw. // …: Erklärung für Menschen, wird beim Übersetzen ignoriert.

int main(void) {: Beginn der Funktion main; hier startet jedes C-Programm. Die geschweifte Klammer öffnet den Block mit den Anweisungen.

return 0;: beendet main und meldet dem Betriebssystem „Programm fehlerfrei beendet“.

Erwartungshorizont zu Aufgabe b)
  • Präprozessor: führt die #-Zeilen aus, fügt also den Inhalt von stdio.h in den Quelltext ein; Kommentare werden entfernt.
  • Compiler: prüft die Syntax (Semikolons, Klammern, bekannte Funktionen) und übersetzt den Quelltext in Maschinencode (Objektcode).
  • Linker: fügt fertige Bibliotheksfunktionen wie printf hinzu und erzeugt die ausführbare Datei.
  • -Wall schaltet zusätzliche Warnungen ein (verdächtige Stellen, die noch kein Fehler sind); -o infotag legt den Namen der fertigen Datei fest: infotag.

Bei diesem fehlerfreien Programm erscheint keine Meldung; im Ordner liegt danach die ausführbare Datei infotag.

Erwartungshorizont zu Aufgabe c)

./infotag startet die ausführbare Datei, die beim letzten Übersetzen entstanden ist. Das Speichern ändert nur den Quelltext infotag.c; die ausführbare Datei enthält noch den alten Maschinencode mit „10 Uhr“. Anders als in Python wird der Quelltext beim Starten nicht neu gelesen.

Konsole · richtige Reihenfolge
$ gcc -Wall infotag.c -o infotag
$ ./infotag
Willkommen im Informatikraum!
Raum 204: Robotik-AG
Beginn: 9 Uhr

Vollständig ist die Antwort mit dem Unterschied Quelltext / ausführbare Datei und dem Hinweis, dass nach jeder Änderung neu übersetzt werden muss.

2

Fehlersuche in der Schulbibliothek

AFB II–III

Tim soll für den Bildschirm am Eingang der Schulbibliothek die Öffnungszeiten ausgeben. Er schreibt schnell die Datei oeffnung.c und übersetzt sie.

C · oeffnung.c (erste Fassung)
#include <stdio.h>

int main(void) {
    printf("Schulbibliothek - Oeffnungszeiten\n");
    printf("Mo bis Do: 8 bis 15 Uhr\n");
    prinft("Fr: 8 bis 13 Uhr\n");
    return 0;
Konsole · erster Versuch
$ gcc -Wall oeffnung.c -o oeffnung
oeffnung.c: In function 'main':
oeffnung.c:6:5: warning: implicit declaration of function 'prinft'; did you mean 'printf'? [-Wimplicit-function-declaration]
    6 |     prinft("Fr: 8 bis 13 Uhr\n");
      |     ^~~~~~
      |     printf
oeffnung.c:7:5: error: expected declaration or statement at end of input
    7 |     return 0;
      |     ^~~~~~

Tim sieht „end of input“, ergänzt am Ende eine schließende Klammer } und übersetzt erneut:

Konsole · zweiter Versuch
$ gcc -Wall oeffnung.c -o oeffnung
oeffnung.c: In function 'main':
oeffnung.c:6:5: warning: implicit declaration of function 'prinft'; did you mean 'printf'? [-Wimplicit-function-declaration]
    6 |     prinft("Fr: 8 bis 13 Uhr\n");
      |     ^~~~~~
      |     printf
/usr/bin/ld: /tmp/ccjLrG9p.o: in function `main':
oeffnung.c:(.text+0x36): undefined reference to `prinft'
collect2: error: ld returned 1 exit status

Zum Vergleich hat Tim dasselbe Programm vorher in Python geschrieben, mit demselben Tippfehler:

Python · oeffnung.py
print("Schulbibliothek - Oeffnungszeiten")
print("Mo bis Do: 8 bis 15 Uhr")
prinft("Fr: 8 bis 13 Uhr")
Konsole · Python
$ python3 oeffnung.py
Schulbibliothek - Oeffnungszeiten
Mo bis Do: 8 bis 15 Uhr
Traceback (most recent call last):
  File "oeffnung.py", line 3, in <module>
    prinft("Fr: 8 bis 13 Uhr")
NameError: name 'prinft' is not defined. Did you mean: 'print'?

Tim meint: „Warnungen sind egal, wichtig sind nur die Errors. Ich lasse -Wall in Zukunft weg, dann ist die Ausgabe übersichtlicher.“

  1. Analysieren Sie die Meldungen beider Übersetzungsversuche: Stellen Sie zu jeder Meldung fest, in welcher Zeile sie entsteht, was ihre Ursache ist und welche Station der Übersetzung (Compiler oder Linker) sie ausgibt, und korrigieren Sie das Programm vollständig.
  2. Vergleichen Sie das Verhalten von C und Python bei Tims Tippfehler. Gehen Sie darauf ein, wann der Fehler jeweils bemerkt wird und was die Nutzerin bzw. der Nutzer davon zu sehen bekommt.
  3. Beurteilen Sie Tims Vorschlag, auf Warnungen und auf -Wall zu verzichten.

Hinweise

Hinweis zu Aufgabe a)
Die Zahlen 6:5 bedeuten Zeile 6, Spalte 5. Meldungen, die mit /usr/bin/ld beginnen, stammen von einem anderen Programm als die übrigen. Warum kommt der zweite Fehler erst beim zweiten Versuch ans Licht?
Hinweis zu Aufgabe b)
Überlegen Sie, wann C den Quelltext prüft (vor dem Start oder während des Laufs) und wie Python das macht. Welche Zeilen erscheinen bei Python trotzdem?
Hinweis zu Aufgabe c)
Mögliche Kriterien: Welchen Hinweis gab die Warnung im ersten Versuch schon? Was passiert, wenn ein Programm trotz Warnung übersetzt wird? Übersicht gegen Sicherheit.„Beurteilen“ heißt: ein eigenes Urteil fällen und mit Fachwissen begründen — nicht nur Vor- und Nachteile aufzählen.

Erwartungshorizont

Erwartungshorizont zu Aufgabe a)
VersuchMeldungZeileUrsacheStation
1warning: implicit declaration of function prinft6Tippfehler: prinft ist keine bekannte Funktion (gemeint: printf)Compiler (nur Warnung)
1error: expected declaration or statement at end of input7Die schließende Klammer } von main fehlt; die Datei endet mitten im Block.Compiler
2warning: implicit declaration … prinft6wie oben, weiterhin nicht behobenCompiler (nur Warnung)
2undefined reference to prinft / ld returned 16Der Linker findet keine Funktion namens prinft in den Bibliotheken.Linker (ld)

Beim ersten Versuch bricht der Compiler wegen der fehlenden Klammer ab, der Linker läuft gar nicht erst. Erst als der Compiler fehlerfrei durchkommt, kann der Linker feststellen, dass es prinft nicht gibt. Die Zeilenangabe 7 zeigt auf die letzte vorhandene Zeile — die Klammer fehlt danach.

C · oeffnung.c (korrigiert, mit gcc -Wall ohne Meldung übersetzt)
#include <stdio.h>

int main(void) {
    printf("Schulbibliothek - Oeffnungszeiten\n");
    printf("Mo bis Do: 8 bis 15 Uhr\n");
    printf("Fr: 8 bis 13 Uhr\n");      // Tippfehler prinft behoben
    return 0;
}                                        // schließende Klammer ergänzt
Konsole
$ gcc -Wall oeffnung.c -o oeffnung
$ ./oeffnung
Schulbibliothek - Oeffnungszeiten
Mo bis Do: 8 bis 15 Uhr
Fr: 8 bis 13 Uhr
Erwartungshorizont zu Aufgabe b)
KriteriumC (Compiler)Python (Interpreter)
Zeitpunkt der Prüfungvor dem Start, das ganze Programm auf einmalerst während des Laufs, Zeile für Zeile
Ausgabe trotz Fehlerkeine — es entsteht gar kein ProgrammZeilen 1 und 2 erscheinen, dann Abbruch mit NameError
Wer sieht den Fehler?nur Tim beim Übersetzenim schlimmsten Fall erst die Person am Bildschirm, wenn die Zeile ausgeführt wird

Gemeinsam ist beiden: Der Tippfehler wird erkannt und mit einem Verbesserungsvorschlag gemeldet („did you mean“). Vorteil C: Fehler in selten ausgeführten Zeilen fallen schon vor der Auslieferung auf. Vorteil Python: Man kann ein halb fertiges Programm schon ausprobieren.

Erwartungshorizont zu Aufgabe c)

Der Vorschlag ist abzulehnen. Gerade in diesem Beispiel hat die Warnung (implicit declaration, „did you mean printf?“) den späteren Linker-Fehler schon im ersten Versuch genau benannt — mit Beachtung der Warnung hätte Tim beide Fehler in einem Durchgang behoben. Warnungen stehen für Stellen, die zwar übersetzt werden, aber sehr wahrscheinlich falsch sind; ein Programm mit Warnungen kann laufen und trotzdem falsche Ergebnisse liefern oder abstürzen. -Wall kostet nichts und findet solche Stellen früh.

Berechtigt ist nur der Wunsch nach Übersicht: Die Lösung ist, Meldungen von oben nach unten abzuarbeiten, nicht, sie abzuschalten. Vollständig ist die Antwort mit einem klaren Urteil, dem Bezug auf Tims Beispiel und mindestens einem allgemeinen Argument.