Übungspaket 17 Der gcc Compiler

Ähnliche Dokumente
Übungspaket 29 Dynamische Speicherverwaltung: malloc() und free()

Übungspaket 23 Mehrdimensionale Arrays

Übungspaket 19 Programmieren eigener Funktionen

Übungspaket 13 Der Datentyp double

Vorlesung Informatik I

Programmieren in C. Macros, Funktionen und modulare Programmstruktur. Prof. Dr. Nikolaus Wulff

Objektorientierung: Klassen und Objekte

2Binden 3. und Bibliotheken

DAP2-Programmierpraktikum Einführung in C++ (Teil 1)

Grundlagen der Programmentwicklung

Die Programmiersprache C

Einleitung Entwicklung in C Hello-World! Konstrukte in C Zusammenfassung Literatur. Grundlagen von C. Jonas Gresens

GI Vektoren

Compiler und Präprozessor (1) Erstellen eines Projektes

GI Grundlagen der Informatik (GI)

Grundlagen. Kapitel 1

Einführung in die C-Programmierung

Übungspaket 24 Zeichenketten

Übersicht. C Modularisierung. Präprozessor, Compiler, Linker. Präprozessor, Compiler, Linker. Präprozessor, Compiler und und Linker Linker

Inhaltsverzeichnis. Grundbegriffe der C-Programmierung Für den HI-TECH C-Compiler

Propädeutikum. Dipl.-Inf. Frank Güttler

Übungspaket 31 Entwicklung eines einfachen Kellerspeiches (Stacks)

Algorithmus: Kochrezept

C/C++ Programmierung

Modellierung und Programmierung

JavaScript. Dies ist normales HTML. Hallo Welt! Dies ist JavaScript. Wieder normales HTML.

Welche Informatik-Kenntnisse bringen Sie mit?

Kompaktkurs C-Programmierung

Praxisorientierte Einführung in C++ Lektion: "Die Compiler-Chain (Vom Quellcode zum ausführbaren Programm)"

Schleifenanweisungen

4. Einfache Programmstrukturen in C Einfache Programmstrukturen in C

Übung 9. Quellcode Strukturieren Rekursive Datenstrukturen Uebung 9

FH München, FB 03 FA WS 06/07. Ingenieurinformatik. Name Vorname Matrikelnummer Sem.Gr.: Hörsaal Platz

Klausur Programmieren in C Sommersemester 2007 Dipl. Biol. Franz Schenk 13. April 2007, Uhr Bearbeitungszeit: 105 Minuten

C Überlebenstraining

Programmierung mit C Zeiger

Präzedenz von Operatoren

Nuetzlicher Kleinkram

Einführung in die Programmierung Wintersemester 2011/12

Es ist für die Lösung der Programmieraufgabe nicht nötig, den mathematischen Hintergrund zu verstehen, es kann aber beim Verständnis helfen.

Microcontroller Praktikum SS2010 Dipl. Ing. R. Reisch

Grundlagen der Informatik - 6. Praktikum

Computergrundlagen Programmieren in C

Zeichendarstellung. Zeichen sind Zahlen (in C) Zeichen und switch

Modul Entscheidungsunterstützung in der Logistik. Einführung in die Programmierung mit C++ Übung 1

Nachname:... Vorname:... MatrNr.:... Klausur PR2. Erstellen Sie eine Struktur für eine Komplexe Zahl mit den Elementen real und imag vom Typ double.

Programmiersprachen Einführung in C. Unser erstes C-Programm. Unser erstes C-Programm. Unser erstes C-Programm. Unser erstes C-Programm

ATM18-Projekt Arbeiten mit CodeVisionAVR C-Compiler Teil 02 - Aufbau eines C-Projektes

Einführung in den Einsatz von Objekt-Orientierung mit C++ I

Schachtelung der 2. Variante (Bedingungs-Kaskade): if (B1) A1 else if (B2) A2 else if (B3) A3 else if (B4) A4 else A

Programmiersprachen Einführung in C

Inhaltsverzeichnis Ubersetzung und Pr aprozessor

Modul Entscheidungsunterstützung in der Logistik. Einführung in die Programmierung mit C++ Übung 4

Grundlagen der Informatik Vorlesungsskript

Programmieren in C. Eine Einführung in die Programmiersprache C. Prof. Dr. Nikolaus Wulff

Ingenieurinformatik Diplom-FA (Teil 2, C-Programmierung)

Grundlagen von C. Ausarbeitung von Jonas Gresens

Variablen und Datentypen

Deklarationen in C. Prof. Dr. Margarita Esponda

C++ Kurs Teil 1. Architektur, Anwendungsspektrum, primitive Datentypen, Funktionsaufrufe, Referenzen, Klassen

Praktikum Ingenieurinformatik. Termin 4. Funktionen, numerische Integration

Übung zu Grundlagen der Betriebssysteme. Einführungsveranstaltung

Praktikum Ingenieurinformatik. Termin 2. Mein erstes C-Programm

Informatik I (D-MAVT)

Programmieren in C. Die C-Standardbibliothek. Prof. Dr. Nikolaus Wulff

Tutorium Rechnerorganisation

Übungen zu C++ Kapitel 1

Programmentwicklung mit C++ (unter Unix/Linux)

Praktikum ASP Blatt 2 6. LEHRSTUHL FÜR RECHNERTECHNIK UND RECHNERORGANISATION Aspekte der systemnahen Programmierung bei der Spieleentwicklung

Programmieren in C. Burkhard Bunk

Übung 1 - Betriebssysteme I

Einleitung. Informationsquellen: - Webseite zur Vorlesung, Abschnitt Informationen zu C und C++ Kurzeinführung in C/C++

Kurze Einführung in die Programmiersprache C++ und in Root

RO-Tutorien 3 / 6 / 12

Elementare Datentypen in C++

CEN1112 Labor Software-Entwicklung

Programmieren in C/C++ und MATLAB

S. d. I.: Programieren in C Folie 4-1. im Gegensatz zu Pascal gibt es in C kein Schlüsselwort "then"

Kapitel 1. Grundlagen

Grundlagen. Wie sind PHP-Dateien aufgebaut?

Bei for-schleifen muss man nur immer bedenken, dass die letzte Anweisung immer erst nach der Ausführung der restlichen Anweisungen der Schleife

Programmierung mit NQC: Kommunikation zwischen zwei RCX

Algorithmen & Programmierung. Steuerstrukturen im Detail Selektion und Iteration

Erste Schritte der Programmierung in C

Übungen zur Vorlesung EidP (WS 2015/16) Blatt 6

C- Kurs 06 Übersetzung & Module

Programmieren. Wie entsteht ein Programm

Einstieg in die Informatik mit Java

Grundlagen. Die Komponenten eines C Programms. Das erste Programm

Programmieren in C. Felder, Schleifen und Fließkommaarithmetik. Prof. Dr. Nikolaus Wulff

Ingenieurinformatik (FK 03) Übung 4

C-Propädeutikum Funktionen

Informatik I. Übung 2 : Programmieren in Eclipse. 5. März Daniel Hentzen

Programm in Source-Files aufteilen Erhöht Lesbarkeit Aufteilung orientier t sich an logischer Struktur des Programms Getrenntes Übersetzen möglich:

Teil IV. Grundlagen der Programmierung

Hello world. Sebastian Dyroff. 21. September 2009

Praktikum Ingenieurinformatik. Termin 6. Mehrdimensionale Felder, Kurvendarstellung mit Excel

Prüfungsvorleistung Datenstrukturen

Kurzeinführung in C. Johannes J. Schneider

Transkript:

Übungspaket 17 Der gcc Compiler Übungsziele: Skript: 1. Sicherer Umgang mit gemischten Ausdrücken 2. Herleiten der unterschiedlichen Datentypen in gemischten Ausdrücken 3. Kenntnis über die implizite Durchführung von Typanpassungen Kapitel: 38, 39 und 40 Semester: Wintersemester 2017/18 Betreuer: Kevin, Theo, Thomas und Ralf Synopsis: Eines haben wir alle bis jetzt sicherlich gelernt, durch Eintippen von gcc quelltext.c wird ein C-Programm in Maschinencode übersetzt und damit lauffähig gemacht. Doch wenn etwas schiefgeht, fangen die Probleme an. Der Compiler selbst ist wie die meisten Programmierwerkzeuge ein recht komplexes Programm. Daher fällt es vielen Programmieranfängern sehr schwer, den Überblick über die einzelnen Teile des Compilers zu behalten und die aufgetretenen Fehlerursachen zu lokalisieren. Um hier Abhilfe zu schaffen, schauen wir uns in diesem Übungspaket den Compiler gcc und seine Komponenten ein wenig genauer an.

Teil I: Stoffwiederholung Aufgabe 1: Grobaufbau des gcc Compilers Durch den Aufruf gcc datei.c werden eigentlich vier größere Programme nacheinander aufgerufen. Benenne diese vier Programme und erläutere kurz, was ihre Aufgaben sind. 1. Programm: Präprozessor Funktion: Der Präprozessor erfüllt im Wesentlichen drei Funktionen: 1. Der Präprozessor ersetzt all #include-direktiven durch die angegebenen Dateien (diese Dateien werden vollständig in den Quelltext eingefügt). 2. Ersetzen aller #define-makros durch ihre entsprechenden Definitionen. 3. Übersetzen bzw. entfernen aller Anweisungen zwischen den #ifdef, #ifndef, #else und #endif Direktiven. 2. Programm: Eigentlicher Compiler (der C-Übersetzer) Funktion: 3. Programm: Assembler Funktion: 4. Programm: Linker Funktion: In dieser Phase wird das C-Programm in denjenigen Assembler-Code übersetzt, der zum gewählten Prozessor gehört. Das Ergebnis ist also eine Datei, die prozessorspezifisch ist. Ergebnis: eine Datei mit der Endung.s Der Assembler wandelt den (prozessorspezifischen) Assembler-Code, der noch lesbare Anweisungen enthält in Maschinencode um. Das Ergebnis ist eine Datei, die nur noch aus unverständlichen Nullen und Einsen besteht, die üblicherweise zu hexadezimalen Zahlen zusammengefasst werden. Ergebnis: eine Datei mit der Endung.o Der Linker fügt den Maschinencode und alle verwendeten Bibliotheken zu einem einzigen lauffähigen Programm zusammen. Erst dieses Programm kann vom Prozessor (in Zusammenarbeit mit dem Betriebssystem) auch wirklich ausgeführt werden. Ergebnis: eine ausführbare Datei mit dem angegeben Namen oder a.out Einführung in die Praktische Informatik, Wintersemester 2017/18 17-1

Aufgabe 2: Die Syntax der Präprozessor-Direktiven Erkläre kurz in eigenen Worten die Syntax der C-Präprozessor-Direktiven: Alle C-Präprozessor-Direktiven fangen mit einem Doppelkreuz # an, werden von einem der Schlüsselwörter include, define, ifdef, ifndef, else oder endif gefolgt und meistens mit einem Argument (Parameter) abgeschlossen. Zwischen dem Zeilenanfang, dem Doppelkreuz #, dem Schlüsselwort und den Argumenten dürfen beliebig viele Leerzeichen, Tabulatoren und Kommentare eingefügt werden. Ferner ist zu beachten, dass eine C-Präprozessor-Direktive in einer Zeile abgeschlossen wird, es sei denn, die Zeile wird mit einem Backslash \ abgeschlossen. Aufgabe 3: Die Präprozessor-Direktiven Erkläre jede Präprozessor-Direktive anhand je eines oder zweier Beispiele: 1. #include Mittels der Direktive #include kann man andere Dateien einbinden. Die #include wird dadurch vollständig durch den Inhalt der angegebenen Datei ersetzt. #include <stdio.h> #include "my.h" 2. #define // Einbinden der Standard Ein-/Ausgabe // Einbinden der eigenen Datei my.h Mittels #define kann man einfache Labels und ganze Makros definieren: #define NAME Cool // mein Name #define HiThere( x ) Hi Daddy x // meine Anrede HiThere( NAME ) Ergibt: Hi Daddy Cool 3. #ifdef... #else...#endif Die #ifdef-direktive erlaubt es, Dinge in Abhängigkeit anderer zu übersetzen. #ifdef my header #else #include "my-header.h" #endif In diesem Falle wird die Datei my header.h nur dann eingebunden, sofern das Label my header noch nicht definiert wurde. Zwischen #if, #else und #endif können beliebige Anweisungen stehen. In den.h-dateien werden oftmals Labels der obigen Form definiert, um das mehrmalige Ausführen eines #include zu vermeiden. 17-2 Wintersemester 2017/18, Einführung in die Praktische Informatik

Teil II: Quiz Aufgabe 1: Die Definition von Namen Gegeben sei folgendes Programmstück: 1 # define Tag Montag /* mein Arbeitstag */ 2 # define WOCHE 34 /* meine Urlaubswoche */ 3 4 # define Telefon 0381 498 72 51 5 # define FAX /* 0049 */ 0381 498 118 72 51 6 7 # define Ferien 8 9 # define MSG " heute geht es mir sehr gut " 10 11 # define NAME1 ein name 12 # define NAME2 NAME1 13 14 # define ZWEI_ZEILEN ZEILE -1 /* das ist die erste Zeile 15 # define ZWEITE_ZEILE hier ist Zeile 2 */ 16 17 # define ENDE " jetzt ist schluss " Finde heraus, welche Namen in obigem Programmstück definiert werden und welche Werte diese haben. Trage die definierten Namen nebst ihrer Werte in folgende Tabelle ein. Zeile Name Wert 1 Tag Montag 2 WOCHE 34 4 Telefon 0381 498 72 51 5 FAX 0381 498 118 72 51 7 Ferien 9 MSG "heute geht es mir sehr gut" 11 NAME1 ein name 12 NAME2 ein name 14 ZWEI ZEILEN ZEILE-1 15 ----------- Hier wird kein Name definiert, denn diese Zeile ist auskommentiert 17 ENDE "jetzt ist schluss" Einführung in die Praktische Informatik, Wintersemester 2017/18 17-3

Aufgabe 2: Definition von Makros Gegeben sei folgendes Programmstück: 1 // macro implemention of the formula : 2* x + 3* y 2 3 # define Formula_1 ( x, y ) 2 * x + 3 * y 4 # define Formula_2 ( x, y ) 2 * (x) + 3 * (y) 5 6 i = Formula_1 ( 1, 2 ); j = Formula_2 ( 1, 2 ); 7 i = Formula_1 ( 4, 2 ); j = Formula_2 ( 4, 2 ); 8 i = Formula_1 ( 1+2, 2+3 ); j = Formula_2 ( 1+2, 2+3 ); 9 i = Formula_1 ( 2+1, 3+2 ); j = Formula_2 ( 2+1, 3+2 ); Notiert in der folgenden Tabelle die Werte der Parameter x und y, das erwartete Ergebnis res = 2 * x + 3 * y, sowie die Resultate, die in den Variablen i und j abgelegt werden: Zeile x y res i j 6 1 2 8 8 8 7 4 2 14 14 14 Zeile x y res i j 8 3 5 21 13 21 9 3 5 21 16 21 Wie werden die Makros vom Präprozessor expandiert (ersetzt)? 6 i = 2 * 1 + 3 * 2; j = 2 * (1) + 3 * (2) ; 7 i = 2 * 4 + 3 * 2; j = 2 * (4) + 3 * (2) ; 8 i = 2 * 1+2 + 3 * 2+3; j = 2 * ( 1+2) + 3 * ( 2+3) ; 9 i = 2 * 2+1 + 3 * 3+2; j = 2 * ( 2+1) + 3 * ( 3+2) ; Überprüft eure Annahme durch Aufruf des Präprozessors. Nehmen wir an, ihr habt die paar Zeilen abgetippt und in der Datei quiz.c gespeichert. Dann einfach cpp quiz.c oder alternativ gcc -E quiz.c aufrufen; die Ergebnisse erscheinen dann direkt auf dem Bildschirm. Überprüft nochmals eure Ergebnisse, wie ihr sie in obiger Tabelle eingetragen habt. Erklärt, sofern sich Unterschiede auftun, was hierfür die Ursachen sind. Welche Schlussfolgerungen zieht ihr daraus für die Definition von Makros? Ursachen: In der Makro-Definition Formula 1 werden die beiden Parameter x und y nicht geklammert. Dadurch kann es sein, dass bei Übergabe von einfachen arithmetischen Ausdrücken die einzelnen Bestandteile aufgrund der Präzedenzregeln nicht so ausgewertet werden, wie man es erwartet. Problembehebung: Bei der Definition (der Implementierung) von Makros sollten die Parameter stets geklammert werden. So werden die Parameter immer zuerst ausgewertet und dann mit anderen Parametern verknüpft. 17-4 Wintersemester 2017/18, Einführung in die Praktische Informatik

Aufgabe 3: Einbinden von (Header-) Dateien Gegeben sei folgendes Programmstück: 1 # include <stdio.h> 2 # include <math.h> 3 4 # define C_TYPES <ctype.h> 5 # include C_TYPES 6 7 //# include < signal.h> Welche Dateien werden dadurch vom Präprozessor eingebunden? Folgende Systemdateien (aus /usr/include) werden eingebunden: stdio.h, math.h und ctype.h Die Datei signal.h wird nicht eingebunden, da diese Zeile auskommentiert ist. Aufgabe 4: Bedingtes Übersetzen Gegeben sei folgendes Programmstück: 1 # define A 4711 2 3 # ifdef A 4 # define N1 17 5 # ifdef B 6 # define N2 2 7 # else 8 # define N2 4 9 # endif 10 # else 11 # define N1 12 12 # define N2-3 13 # endif 14 15 int i = N1 * N2; Welche Labels werden mit welchen Werten definiert, welchen Wert erhält die Variable i? Zeile Label Wert 1 A 4711 4 N1 17 Zeile Label Wert 8 N2 4 15 i 68 Einführung in die Praktische Informatik, Wintersemester 2017/18 17-5

Teil III: Fehlersuche Aufgabe 1: Praktische Fehlersuche Das folgende Programm soll den Text Fehler beheben drei Mal ausgeben, jeweils eine Ausgabe pro Zeile. Diesmal war unser Starprogrammierer Dr. Bit-Byte zugange. Aber auch ihm sind einige Fehler unterlaufen. Finde und korrigiere diese. Zeige anschließend mittels einer Handsimulation, dass dein Programm korrekt arbeitet. 1 # define ANZAHL 3; 2 # define LOOP_CONDITION ( fehler >= 0) 3 # define MSG " Fehler " eheben " 4 5 int main ( int argc, char ** argv ); 6 { 7 int fehler = ANZAHL ; 8 do 9 printf ( MSG ); fehler = - 1; 10 while ( LOOP_CONDITION ); 11 return 0; 12 } Zeile Fehler Erläuterung Korrektur 0 #include fehlt Die Datei stdio.h wird nicht eingebunden. Wir brauchen sie aber, da wir etwas ausgeben wollen. #include <stdio.h> 1 Das Semikolon scheint zu viel zu sein. Aber in der Initialisierung in Zeile 7 ist es dennoch ok (aber unschön). 2 >= statt > Im Verbindung mit der do-while-schleife in den Zeilen 8 bis 10 ergeben sich vier statt drei Schleifendurchläufe. (fehler>0) 3 " statt b Hier scheint ein einfacher Tippfehler vorzuliegen. beheben 5 ; zu viel Bei der Funktionsdefinition darf am Ende kein ; stehen. Dieses ist nur bei Funktionsdeklarationen erlaubt, die dem Compiler den Namen und die Signatur der Funktion bekannt machen. argv ) 8/10 {} fehlen Da die do-while-schleife mehr als eine Anweisung ausführen soll, müssen sie durch {} geklammert werden. 3 {... } 9 fehler fehlt Da der Wert der Variablen fehler um eins reduziert werden soll, muss sie auch auf der rechten Seite auftauchen. fehler = fehler - 1 17-6 Wintersemester 2017/18, Einführung in die Praktische Informatik

Programm mit Korrekturen: 1 # include <stdio.h> 2 3 # define ANZAHL 3 4 # define LOOP_CONDITION ( fehler > 0) 5 # define MSG " Fehler beheben \ n" 6 7 int main ( int argc, char ** argv ) 8 { 9 int fehler = ANZAHL ; 10 do { 11 printf ( MSG ); 12 fehler = fehler - 1; 13 } while ( LOOP_CONDITION ); 14 return 0; 15 } Vor der Handsimulation ist es eine gute Übung, sich das Programm zu überlegen, das der Präprozessor aus der.c-datei generiert: Ergebnis nach Abarbeitung durch den Präprozessor: 7 int main ( int argc, char ** argv ) 8 { 9 int fehler = 3; 10 do { 11 printf ( " Fehler beheben \n" ); 12 fehler = fehler - 1; 13 } while ( ( fehler > 0) ); 14 return 0; 15 } Handsimulation: Zeile 9 11 12 13 11 12 13 11 12 13 14 fehler 3 2 2 1 1 0 0 printf() Fehler beheben Fehler beheben Fehler beheben Einführung in die Praktische Informatik, Wintersemester 2017/18 17-7

Teil IV: Anwendungen Aufgabe 1: Fehler Finden und Eliminieren Es ist ganz normal, dass man beim Entwickeln und Eintippen eines Programms viele Tippfehler macht. Da der Compiler ein recht pingeliger Zeitgenosse ist, findet er viele dieser Tippfehler und gibt entsprechende Fehlermeldungen und Hinweise aus. Die Kunst besteht nun darin, dieser Ausgaben richtig zu deuten und die wirklichen Fehlerursachen zu finden. Um dies ein wenig zu üben, greifen wir nochmals das fehlerhafte Programm aus dem vorherigen Abschnitt (vorherige Seite) auf, wobei wir davon ausgehen, dass ihr sowieso alle Fehler gefunden habt. Arbeite nun wie folgt: Arbeitsanleitung: 1. Tippe das fehlerhafte Programm ab und speichere es in einer Datei deiner Wahl. 2. Übersetze das fehlerhafte Programm mittels gcc. 3. Fahre mit Arbeitsschritt 6 fort, falls der Compiler keine Fehlermeldung oder Warnung ausgegeben hat. 4. Lese die erste(n) Fehlermeldung(en) aufmerksam durch und korrigiere einen Fehler. 5. Gehe zurück zu Arbeitsschritt 2. 6. Starte das Programm und überprüfe, ob es korrekt arbeitet. 7. Sollte das Programm korrekt arbeiten gehe zu Schritt 10 8. Korrigiere einen inhaltlichen Fehler (Semantikfehler). 9. Gehe zurück zu Arbeitsschritt 2. 10. Fertig! Hinweis: Diese Herangehensweise empfiehlt sich auch in Zukunft :-)! 17-8 Wintersemester 2017/18, Einführung in die Praktische Informatik

Aufgabe 2: Eigene Makro-Definitionen Definiere je ein Makro für die folgenden drei Formeln (Lösungen siehe unten): f(x) = 3x 2 + x/2 1 g(x, y) = x 2 3xy + y 2 h(x, y, z) = 2x 3 3y 2 + 2z Zu welchen Ergebnissen führen die folgenden drei Aufrufe (Einsetzen)? Aufruf Resultat Mathematik Resultat C-Programm f(1 + z) 3(1 + z) 2 + (1 + z)/2 1 3*(1 + z)*(1 + z) + (1 + z)/2-1 g(x, A + 1) x 2 3x(A + 1) + (A + 1) 2 x*x - 3*x*(A + 1) + (A + 1)*(A + 1) h(a, b, a + b) 2a 3 3b 2 + 2(a + b) 2*a*a*a - 3*b*b + 2*(a + b) Überprüft eure Makro-Definitionen durch Eintippen eines kleinen Programmstücks und Aufruf des Präprozessors (entweder mittels cpp <datei>.c oder gcc -E <datei>.c). Programmstückchen: 1 # define f(x) 3*( x)*(x) + (x)/2-1 2 # define g(x, y) (x)*(x) - 3*( x)*(y) + (y)*(y) 3 # define h(x, y, z) 2*( x)*(x)*(x) - 3*( y)*(y) + 2*( z) 4 5 f(1 + z) 6 g(x, A + 1) 7 h(a, b, a + b) Ausgabe des Präprozessors: 1 3*(1 + z) *(1 + z) + (1 + z)/2-1 2 (x)*(x) - 3*( x)*(a + 1) + (A + 1) *(A + 1) 3 2*( a)*(a)*(a) - 3*( b)*(b) + 2*( a + b) Einführung in die Praktische Informatik, Wintersemester 2017/18 17-9