Freitagsrunde C-Kurs 2012 Compiler Präprozessor Header Files Tutorium 3 ThisworkislicensedunderaCreativeCommonsAttribution NonCommercial ShareAlike3.0License
Gliederung Compiler Präprozessor Header Files
HelloWorldRevisited Datei hello.c Kommandozeile $ gcc -o hello hello.c $./hello Hello, World! $ #include <stdio.h> int main() { } printf("hello, World!\n"); return 0; hellokannnachderkompilierungwiejedesandere Unix Kommandoausgeführtwerden 3
DerC Compiler 4
KompilierungalsmehrstufigerProzess Quellcode-Dateien hello.c Header-Dateien stdio.h Präprozessor Bibliotheken /usr/lib/libc.a Linker Compiler Objektdateien Modifizierter Quellcode hello.o ausführbaredatei hello 5
HelloWorldbestehendausmehrerenDateien Dateimain.cDateienhello.cundbye.c externhello(char*who); externbye(char*who); intmain(){ #include<stdio.h> hello(char*who){ printf("hello,%s!\n",who); } hello("world"); bye("world"); return0; } #include<stdio.h> bye(char*who){ printf("bye,%s!\n",who); } 6
SeparateKompilierung $ ls bye.c hello.c main.c $ gcc -c main.c $ gcc -c hello.c $ gcc -c bye.c $ ls bye.c hello.c main.c bye.o hello.o main.o $ 7
Linken $ gcc -o hello main.o hello.o bye.o $./hello Hello, World! Bye, World! $ 8
Makefiles Datei Makefile all: main main: main.o hello.o bye.o gcc -o hello main.o hello.o bye.o hello.o: hello.c gcc -c hello.c bye.o: bye.c gcc -c bye.c main.o: main.c gcc -c main.c clean: rm -f hello main.o hello.o bye.o 9
Übungsaufgabe Kopiert euch die Beispieldateien und das Makefile in einen Ordner. Kompiliert die Dateien zunächst per Hand separat und linkt sie dann zusammen! Führt jedesmal ls aus! Löscht jetzt alle Objekt- und ausführbaren Dateien! Führt make aus und seht euch die Ausgabe an! Löscht die Datei bye.o! Führt erneut make aus und seht euch die Ausgabe an! 10
TypenvonFehlern Präprozessor Fehler,z.B. falschgeschriebenepräprozessoranweisung undefiniertesymbolischekonstante Compiler Fehler,z.B. Syntaxfehler Typfehler Linker Fehler,z.B. undefinedreferenceto`hello' collect2:ldreturned1exitstatus Laufzeitfehler,z.B. dividebyzero Speicherzugriffsfehler:segmentationfault/buserror 11
DerPräprozessor 12
Präprozessoranweisungen am Zeichen # zu Beginn der Anweisung zu erkennen der Präprozessor erkennt nur Zeilen beginnend mit # 13
Präprozessoranweisungen am Zeichen # zu Beginn der Anweisung zu erkennen der Präprozessor erkennt nur Zeilen beginnend mit # Einfügen von Dateien: Ersetzen von Text (Makros): #include #define Bedingte Kompilierung: #if, #ifdef, #ifndef, #else, #elif, #endif 14
Präprozessoranweisungen am Zeichen # zu Beginn der Anweisung zu erkennen der Präprozessor erkennt nur Zeilen beginnend mit # Einfügen von Dateien: Ersetzen von Text (Makros): #include #define Bedingte Kompilierung: #if, #ifdef, #ifndef, #else, #elif, #endif 15
Header Dateien 16
Header Dateien #include<stdio.h> hello(char*who){ printf("hello,%s!\n",who); } externhello(char*who); externbye(char*who); intmain(){ hello("world"); #include<stdio.h> bye(char*who){ printf("bye,%s!\n",who); } bye("world"); return0; } 17
Header Dateien HeaderDateienerkenntmananderEndung".h SiesindTeilvonSchnittstellenzwischenSystemen Sieenthalten: Funktions Deklarationen globalevariablen symbolischekonstanten Makros Datentypen(z.B.Strukturen) 18
InkludierenvonHeader Dateien #include <name> sucht zuerst im Verzeichnis der Systemdateien erst dann im Verzeichnis der Quelldatei wird normalerweise verwendet, um Headerdateien, die vom System geliefert werden, einzubinden (z.b. #include <stdio.h>) #include "name" sucht zuerst im Verzeichnis der Quelldatei erst dann im Verzeichnis der Systemdateien wird normalerweise verwendet, um selbstgeschriebene Header-Dateien einzubinden (z.b. #include "debug.h") 19
I Compileroption(gcc) ErweitertbeimÜbersetzeneinesProgrammesdie ListederVerzeichnisse,indenennacheinerDatei gesuchtwird. gcc Iincludehello.c suchtnachstdio.hzuerstalsinclude/stdio.h,underst dannals/usr/include/stdio.h. 20
E Compileroption(gcc) Was geschieht nun aber eigentlich beim Inkludieren eines Files? Mit -E könnt ihr euch die Ausgabe des Präprozessors ansehen. Probiert's aus: Kommandozeile: $ gcc -E hello.c 21
Präprozessor OutputvonHelloWorld #304"/usr/include/stdio.h"34 externintprintf( constchar* restrict format,...); 22
Problem:Mehrfachinklusion Datei foo.h Datei bar.h #include bar.h #include baz.h... Datei baz.h 23
Problem:Mehrfachinklusion Datei foo.h Datei bar.h #include bar.h #include baz.h #include baz.h...... Datei baz.h 24
Problem:Mehrfachinklusion Datei foo.h Datei bar.h #include bar.h #include baz.h #include baz.h...... Datei baz.h 25
Problem:Mehrfachinklusion Datei foo.h Datei bar.h #include bar.h #include baz.h #include baz.h...... Datei baz.h #include bar.h... 26
Problem:Mehrfachinklusion Datei foo.h Datei bar.h #include bar.h #include baz.h #include baz.h...... Datei baz.h #include bar.h... 27
Makros Compiler Präprozessor Compiler EinfügenvonDateien: Linker Präprozessor #include ErsetzenvonText(Makros): #define BedingteKompilierung: #if,#ifdef,#ifndef,#else,#elif,#endif 28
ParameterloseMakros Syntax:#defineNAME[replacement] PräprozessorersetztvorderKompilierungjedes VorkommenvonNAMEmitdemErsetzungstext Fehltdasreplacement,soistderNAMEdemSystem imfolgendenbekannt,anstattundefiniertzusein UmdensemantischenUnterschiedklarzumachen, solltenmakrosimmergrossgeschriebenwerden! EinausführlichesBeispielwerdenwirspäterbetrachten 29
MakrosmitParametern Syntax: kein Leerzeichen Leerzeichen #definename(dummy1[[,dummy2],...])...dummy1... Parameterliste Tokenstring Beispiel: #definesizeof(array)sizeof(array)/sizeof(array[0]) 30
BedingteKompilierung Compiler Präprozessor Compiler EinfügenvonDateien: Linker Präprozessor #include ErsetzenvonText(Makros): #define BedingteKompilierung: #if,#ifdef,#ifndef,#else,#elif,#endif 31
BedingteKompilierung 32
BedingteKompilierung #ifdef_win32 /*dowindowsspecificstuffhere*/ #endif #ifdef APPLE /*domacspecificstuffhere*/ #endif #ifdef linux /*dolinuxspecificstuffhere*/ #endif 33
VermeidungvonMehrfachinklusion Datei foo.h #ifndef FOO_H #define FOO_H extern int foo(int x, int y); #endif Was bewirkt nun dieser Code? 34
Beispiel:Debugging intdebug=1; intmain(){ if(debug) printf("enteringmain...\n ); if(debug) printf("exitingmain...\n ); return0; } 35
EineinfachesDebuggingMakro Dateidebug.h #include<stdio.h> #definedebug #ifdefdebug #definelogprintf #else #definelogif(0)printf #endif 36
UnserneuesHelloWorld Dateihello.c #include debug.h intmain(){ LOG("HelloWorld!\n"); return0; } 37
OutputdesPräprozessors(gcc) $gcc Ehello.c...748weitereZeilen #11"hello.c" intmain(){ printf("hello,world!\n"); return0; } $ 38
defineperkommandozeile(gcc) gcc[ Dmacro[=defn]...]infile $gcc DDEBUGhello.c $gcc DDEBUG DVERBOSE=2hello.c 39
UnserneuesDebuggingMakro Dateidebug.h #include<stdio.h> #ifndefverbose #defineverbose0 #endif #ifdefdebug #definelogprintf #else #definelogif(0)printf #endif 40
UnserneuesHelloWorldmitDebugLevels Dateihello.c #include debug.h intmain(){ if(verbose>=1)log("helloworld!\n"); return0; } 41
DebugLevelsmitbedingterKompilierung Dateihello.c #include debug.h intmain(){ #ifverbose>=1 LOG("HelloWorld!\n"); #endif return0; } 42
Übungsaufgabe Schreibt ein Makefile für unser neues Hello-WorldBeispiel! Definiert targets release, debug0 und debug1 für Debug-Builds mit verschiedenen verbosity levels! Beachtet, dass auch header-dateien als Abhängigkeiten angegeben werden müssen! Kompiliert euren Code für verschiedene DebugLevels und überzeugt euch anhand des Konsolensowie des Präprozessoroutputs, dass er funktioniert 43
Danke! 44