• Keine Ergebnisse gefunden

¨Ubungspaket 28 Module und getrenntes ¨Ubersetzen

N/A
N/A
Protected

Academic year: 2021

Aktie "¨Ubungspaket 28 Module und getrenntes ¨Ubersetzen"

Copied!
9
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Ubungspaket 28 ¨

Module und getrenntes ¨ Ubersetzen

Ubungsziele: ¨

1. Verteilen von Programmteilen auf mehrere Dateien 2. Richtige Verwendung der Header-Dateien

3. Richtiger Umgang mit dem C-Compiler Skript:

Kapitel: 55 und 39 sowie insbesondere auch ¨ Ubungspaket 17 Semester:

Wintersemester 2021/22 Betreuer:

Thomas, Tim und Ralf Synopsis:

Im Gegensatz zu vielen klassischen Programmiersprachen bietet C die

M¨ oglichkeit, das Programm auf mehrere Dateien zu verteilen. Diese

Verteilung gestattet es, nur diejenigen Dateien zu ¨ ubersetzen, die sich

auch wirklich ge¨ andert haben; die anderen .o-Dateien k¨ onnen bleiben,

wie sie sind. Diese Option f¨ uhrt zu ¨ ubersichtlichen Quelltext-Dateien

und kann die notwendige ¨ Ubersetzungszeit bei großen Programmen

deutlich reduzieren. Allerdings tritt beim Aufteilen des Quelltextes auf

mehrere Dateien das Problem der Konsistenzhaltung auf: es kann vor-

kommen, dass eine Funktion in einer Datei anders definiert ist, als sie

in einer anderen Datei aufgerufen wird. Hier hilft der richtige Um-

gang mit den Header-Dateien und den #include-Direktiven, was wir

im Rahmen dieses ¨ Ubungspaketes probieren wollen.

(2)

Teil I: Stoffwiederholung

Aufgabe 1: Fragen zum Compiler

Wie heißen die vier Teilprogramme, die der Compiler nacheinander aufruft?

1. Pr¨aprozessor 2. (eigentlicher) Compiler

3. Assembler 4. Linker/Binder

Welcher Teil des Compilers bearbeitet die #include-Direktiven? Der Pr¨aprozessor Welche Phasen beinhaltet der eigentliche ¨Ubersetzungsvorgang? Phasen 1-3 Mittels welcher Option h¨ort der Compilervor dem Binden auf? -c

Gib hierf¨ur ein Beispiel. gcc -c datei.c

In welcher Datei landet das Ergebnis der eigentlichen ¨Ubersetzung? datei.o

Was ”weiß“ der Compiler nach dem ¨Ubersetzen von datei.c? Rein garnichts.

Nehmen wir nun an, wir w¨urden zwei Dateien ¨ubersetzen. Was

”weiß“ der Compiler von der ersten Datei, beim ¨Ubersetzen der zweiten, wenn wir folgende Kommandos verwenden?

gcc -c datei-1.cund gcc -c datei-2.c Absolut nichts gcc -c datei-1.c datei-2.c Ebenso wenig

Erkl¨are nochmals kurz in eigenen Worten, was die #include-Direktive macht.

Der Compiler ersetzt die #include-Direktive 1:1 durch die angegebene Datei.

Vervollst¨andige die beiden folgenden Beispiele:

#include-Direktive Effekt

#include <math.h> F¨ugt die Datei math.h ein.

#include "vowels.h" F¨ugt die Datei vowels.h ein; diese wird zun¨achst im aktuellen Verzeichnis gesucht.

(3)

Teil II: Quiz

Aufgabe 1: ¨ Ubersetzen und Binden (Linken)

Im Folgenden gehen wir davon aus, dass wir eine Reihe von Dateien haben und diese mittels des C-Compilers ¨ubersetzen und/oder binden wollen. in der ersten Spalte steht jeweils das auszuf¨uhrende Kommando. In der zweiten soll jeweils stehen, welche Dateien ¨ubersetzt werden. In der dritten Spalte soll stehen, ob ein lauff¨ahiges Programm zusammengebunden wird und wie ggf. dessen Name lautet. Vervollst¨andige die fehlenden Spalten.

Kommando ubersetzte Dateien¨ gebundenes Programm

gcc datei-1.c datei-1.c a.out

gcc datei-1.c -o badman datei-1.c badman

gcc -c a.c b.c a.c, b.c ----

gcc a.o b.o ---- a.out

gcc -o temperatur x.c y.o x.c (y.ogibt es schon) temperatur gcc -c inge.c peter.c inge.c, peter.c ----

gcc -o supi supi.c supi.c supi

(4)

Teil III: Fehlersuche

Aufgabe 1: Eine einfache verteilte Anwendung

Chefprogrammierer Dr. Modell-Hammer hat versucht, eine erste kleine verteilte An- wendung zu schreiben. Dabei hat er folgende Struktur im Sinn gehabt:

test.c main()

hello.h hello.c hello()

¨Ubersetzen:

gcc -x test test.c hello.h hello.c

In dieser Struktur befindet sich in der Datei test.c das Hauptprogramm, das seinerseits die Funktion hello() aufruft, die einen netten Begr¨ußungstext ausgibt. Diese Funktion gibt den Geburtstag, der als Struktur definiert ist, an die aufrufende Stelle zur¨uck. Leider hat auch Dr. Modell-Hammerein paar kleine Fehler gemacht . . . er ist desperate . . . Das Hauptprogramm: test.c

1 # i n c l u d e < s t d i o . h >

2 # i n c l u d e " h e l l o . c "

3

4 int m a i n ( int argc , c h a r ** a r g v )

5 {

6 s t r u c t b i r t h d a t e b i r t h = h e l l o ( " f r i d a " ) ; 7 p r i n t f ( " my b i r t h d a y is : % d . % d . % d \ n " ,

8 b i r t h . day , b i r t h . month , b i r t h . y e a r ) ;

9 }

Die Header-Datei: hello.h

1 s t r u c t b i r t h d a t e h e l l o ( c h a r * n a m e ) ; Das Modul: hello.c

1 # i n c l u d e < s t d i o . h >

(5)

Zeile Fehler Erl¨auterung Korrektur hello.c: 4 struct

...

Das geht leider schief. Der Compiler kann die Datei hello.c einwandfrei ¨ubersetzen. Da aber im Regelfalle alle anderen Dateien nicht eine .c sondern eine .h-Datei einbinden, bekommt der Compiler dort nicht mit, was struct birthdate sein soll. Mit anderen Worten: Diese Definition geh¨ort in die .h-Datei, damit der Compiler auch bei den anderen.c-Dateien weiß, was mitstruct birthdate gemeint ist.

Verschieben nach

hello.h

. . . .

hello.h: 1 Fehlende Definition

Wie eben erl¨autert, muss hier die Definition f¨ur die Struktur birthdate hin.

dito.

. . . .

test.c: 2 hello.c Das Einbinden einer anderen.c-Datei wollen wir ja gerade nicht. Dann h¨atten wir hier gleich alle Zeilen der Datei hello.c hinschreiben k¨onnen.

Wir wollen ja gerade, dass die C-Anweisungen in getrennten Dateien bleiben. Daher bindet man hier ¨ublicherweise eine Header-Datei.hein. Diese dient dann dem Compiler, damit er weiß, was los ist und somit leichter Fehler entdecken kann, was wiederum uns bei der Programmentwicklungsehr hilft.

dito.

. . . .

Kommando hello.h zu viel

Beim Aufruf des Compilers m¨ussen wir die .c- Dateien angeben; die .h-Dateien werden durch die #include-Direktiven vom C-Compiler auto- matisch eingebunden.

hello.h streichen

Aufgrund seiner L¨ange haben wir das komplette Programm auf der n¨achsten Seite abge- druckt.

(6)

Das Hauptprogramm: test.c 1 # i n c l u d e < s t d i o . h >

2 # i n c l u d e " h e l l o . h "

3

4 int m a i n ( int argc , c h a r ** a r g v )

5 {

6 s t r u c t b i r t h d a t e b i r t h = h e l l o ( " f r i d a " ) ; 7 p r i n t f ( " my b i r t h d a y is : % d . % d . % d \ n " ,

8 b i r t h . day , b i r t h . month , b i r t h . y e a r ) ;

9 }

Die Header-Datei: hello.h

1 s t r u c t b i r t h d a t e { int day ; int m o n t h ; int y e a r ; };

2

3 s t r u c t b i r t h d a t e h e l l o ( c h a r * n a m e ) ;

Das Modul: hello.c

1 # i n c l u d e < s t d i o . h >

2 # i n c l u d e " h e l l o . h "

3

4 s t r u c t b i r t h d a t e h e l l o ( c h a r * n a m e )

5 {

6 s t r u c t b i r t h d a t e b i r t h ;

7 p r i n t f ( " h e l l o % s , my d a r l i n g !\ n " , n a m e ) ;

8 b i r t h . day = 30; b i r t h . m o n t h = 2; b i r t h . y e a r = 1 9 9 1 ;

9 r e t u r n b i r t h ;

10 }

Kommando zum ¨Ubersetzen: gcc -o test test.c hello.c

(7)

Teil IV: Anwendungen

Ziel dieses ¨Ubungspaketes ist es, ein kleines Programm zu entwickeln, das auf zwei Da- teien verteilt ist und dennoch zu einem lauff¨ahigen Programm zusammengebunden wird.

Um keine weiteren Probleme zu erzeugen, verwenden wir das Programm zum Z¨ahlen von Vokalen aus ¨Ubungspaket 24.

Vorbemerkung

Bevor wir mit der Arbeit loslegen, wiederholen wir hier als Lehrk¨orper nochmals drei wesentliche Punkte aus dem Skript:

1. Dem Compiler ist es es v¨ollig egal, wo sich welche Funktionen befinden. Er muss aber wissen, in welchen Dateien sie kodiert sind, damit er sie ¨ubersetzen und am Ende zu einem Programm zusammenbinden kann.

2. Wenn der Compiler mehrere Dateien ¨ubersetzt, egal ob mittels eines oder mehrerer Kommandos, dann ¨ubersetzt er die angegebenen Dateien nacheinander. Nach dem Ubersetzen jeder einzelnen Datei schreibt er das Ergebnis in eine Ergebnis-Datei¨ (meist eine.o-Datei) und vergisst sofort alles! Das bedeutet folgendes: Der Compiler merkt sich nicht irgendwelche Definitionen und/oder Funktionsk¨opfe; wir m¨ussen selbst daf¨ur sorgen, dass er alles zur richtigen Zeit mitbekommt.

3. Die Verwendung von .h-Dateien ist nicht notwendig aber hilft uns und dem Com- piler. In einer .h-Datei stehen ¨ublicherweise Konstantendefinitionen (beispielswei- se #define SIZE 10) und Funktionsdeklarationen (beispielsweise int my ia prt(

FILE *fp, int *a, int size );), die auch Prototypen genannt werden. Durch diese Deklarationen kann der Compiler Inkonsistenzen feststellen und uns diese mit- teilen, wodurch die Programmentwicklung f¨ur uns stark vereinfacht wird.

Aufgabe 1: Getrenntes ¨ Ubersetzen am Beispiel

1. Aufgabenstellung

Wir wollen wieder die Anzahl Vokale z¨ahlen, die sich in einer Zeichenkette befinden.

Damit wir nicht von vorne anfangen m¨ussen, greifen wir auf die Programme aus den Ubungspaketen¨ 24 (Anwendungsteil, Aufgaben 2) und 25 zur¨uck. Aber diesmal pa- cken wir die damals entwickelte Funktionint vokale( char * str )in einegeson- derte Datei. Beide Dateien wollen wir getrennt ¨ubersetzen und zu einem Programm zusammenbinden. Das Testen erledigen wir mittels desargc/argv-Mechanismus.

(8)

Aufgabe : Trennen von Funktion (Funktionalit¨at) und Hauptprogramm in meh- rere Dateien

Eingabe : keine; die Testdaten werden ¨uberargc/argv ¨ubergeben Ausgabe : Zahl der Vokale je Zeichenkette

Sonderf¨alle : keine 3. Entwurf

Da wir diesmal die

”Programmzeilen“ trennen wollen, ben¨otigen wir ein paar ¨Uber- legungen zum Thema Entwurf, wobei wir ein wenig helfen wollen ;-)

Wir wollen also das Hauptprogramm (main) vom Z¨ahlen der Vokale (vokale()) tren- nen. Ferner wollen wir sicherstellen, dass der Compiler ¨uberall die selbe Vorstellung bez¨uglich Funktionstyp und Parameter (Signatur) von der Funktion vokale() hat.

Wie viele Dateien ben¨otigen wir? Drei Dateien

Definiere die ben¨otigten Dateinamen: main.c,vokale.c und vokale.h 4. Implementierung

Hier brauchen wir uns keine weiteren Gedanken machen, da wir bereits alle notwen- digen Programmzeilen in den ¨Ubungspaketen 24und 25 entwickelt haben.

5. Kodierung

Zuerst die Schnittstelle vokale.h:

1 /*

2 * d a t e i : v o k a l e . h

3 * das h i e r ist die s c h n i t t s t e l l e f u e r v o k a l e . c 4 */

5

6 int v o k a l e ( c h a r * str ) ; // t h a t ’ s it ! s i m p l e as t h i s Da wir diese Datei jetzt ¨uberall mittels #include "vokale.h" einbinden, kann der

(9)

Nun die Implementierung der Funktion vokale():

1 /*

2 * d a t e i : v o k a l e . c

3 * das ist die i m p l e m e n t i e r u n g der f u n k t i o n v o k a l e () 4 */

5

6 # i n c l u d e " v o k a l e . h "

7

8 int v o k a l e ( c h a r * str )

9 {

10 int cnt ;

11 if ( str != 0 ) // if ( str ) w o u l d be f i n e as w e l l

12 {

13 for ( cnt = 0; * str ; str ++ )

14 if ( * str == ’ a ’ || * str == ’ A ’ ||

15 * str == ’ e ’ || * str == ’ E ’ ||

16 * str == ’ i ’ || * str == ’ I ’ ||

17 * str == ’ o ’ || * str == ’ O ’ ||

18 * str == ’ u ’ || * str == ’ U ’ )

19 cnt ++;

20 }

21 e l s e cnt = -1;

22 r e t u r n cnt ;

23 }

Und schließlich das Hauptprogramm main():

1 /*

2 * d a t e i : m a i n . c

3 * h i e r b e f i n d e t s i c h das h a u p t p r o g r a m m 4 */

5

6 # i n c l u d e < s t d i o . h >

7 # i n c l u d e " v o k a l e . h " // n i c h t v o k a l e . c !!!

8

9 int m a i n ( int argc , c h a r ** a r g v )

10 {

11 int i ;

12 for ( i = 1; i < a r g c ; i ++ )

13 p r i n t f ( " str = ’% s ’ v o w e l s =% d \ n " ,

14 a r g v [ i ] , v o k a l e ( a r g v [ i ] ) ) ;

15 }

Referenzen

ÄHNLICHE DOKUMENTE

datAusgabe.open(„c:\\hallo.txt“, ios::out); (Vorhandene Datei wird überschrieben) datAusgabe.open(„c:\\hallo.txt“, ios::app); (anhängen an

Ein liberaler Theologe als Hauptpastor und an der Hamburger Universität 146 Benno Jacobs Wirken in der Hamburger Franz-Rosenzweig-Gedächtnisstiftung 150 Heinz Beckmann im

Schreibe eine Methode berechneSchrittweitenNeu(), welche z.B. nach einer Veränderung des Drehwinkels deltaX und deltaY neu berechnet. Die Klasse STAUBSAUGER erbt zwar von der

Im Folgenden gehen wir davon aus, dass wir eine Reihe von Dateien haben und diese mittels des C-Compilers ¨ ubersetzen und/oder binden wollen.. in der ersten Spalte steht jeweils

Das heißt, dass man nur eine Funktion ben¨ otigt, die von einem File Pointer liest und auf den anderen schreibt.. Sollten mehrere Da- teien gelesen werden, muss man diese Funktion

Zwischen je zwei Positionen von Liniensegmenten gibt es eine optimale Bewegung von einem der folgenden Typen:.. maximal zwei Rotationen und eine geradlinige

Die Metallteile in der verbleibenden Schlacke müssen weitestgehend entfernt und dem Rohstoffkreislauf zugeführt werden, bevor das Material in die Deponie eingelagert werden

Das Finanzministerium emp- fiehlt, die Steuererklärung elek- tronisch abzugeben. Denn die elektronische Abgabe bietet für alle Beteiligten Vorteile: Das Fi- nanzamt muss die