Hallo Ich such ein gutes Textbuch über Programmierung in C++, das einem erklärt, wie man selbstgeschriebene Headerfiles organisiert, also was kommt in das .h , was kommt in das .cpp , in welcher Reihenfolge weden die #include Anweisungen in die einzelnen Dateien gesetzt und wie verdaut der Compiler bzw. Linker das ganze. Tips, wie man es macht hab ich schon ein paar gelesen, aber ich würde das Ganze gerne insgesamt verstehen. Bücher in englisch sind mir genauso recht, da ich englische Originale den übersetzten Versionen vorziehe. Vielen Dank dafür
Wahrscheinlich findest du dazu mehr in jedem C-Buch. Der Unterschied ist minimal. In C immer und in C++ weitestgehend ist es so, daß alle Deklarationen in die .h kommen und die Definitionen in die .c - und zwar gleichermaßen für Funktionen wie für globale Variablen. Typdefinitionen und Makros landen in der .h, wenn sie in mehreren Quelltexten genutzt werden. In C++ kommt inline dazu, sei es explizit oder bei innnerhalb von class{ ... } definierten Methoden implizit. Dann stehen auch diese Methoden (also ggf. mit der gesamten class{ ... }) in der .h. Vielleicht reicht dir das schon: http://www.wachtler.de/ck/16_Aufteilung_mehrere_Quell.html
versuchs mal mit: "C - A Software Engineering Approach" von P. Darnell gruss, tom.
Im Grunde ist es sehr einfach: Du teilst dein Projekt in Module ein. Ein Modul ist eine Einheit, die einen bestimmten Themenkreis bearbeitet. Wie zb Stringverwaltung oder Kundendaten oder was auch immer. Dann überlegst du, welche Teile deines Moduls den Verwender des Moduls interessieren, welche Datentypen muss der kennen wenn das Modul beispielsweise irgendwelche Strukturen oder Klassen definiert, welche Funktionen muss ein Verwender benutzen können, welche globalen Variablen muss ein Verwender sichtbar und zugreifbar haben. All das kommt ins Header File. Alles andere kommt ins cpp-File (oder C File, das Prinzip ist dasselbe). Dazu überlegt man noch, welche weiteren Includes jeweils nötig sind, damit das Header File bzw cpp-File in sich vollständig ist. Wird in einem Header File ein Datentyp 'hamstibamsti' benutzt, der nicht Teil dieses Moduls ist, dann setzt man einen entsprechenden Include an den Anfang. Einfach nach der Regel vorgehen: Der Compiler arbeitet den Code von oben nach unten ab und verwendet werden kann nur das was bereits bekannt ist. Ein Datentyp "hamstibamsti" muss also deklariert werden ehe er das erstmal zb in einer Klasse benutzt werden kann. Daher muss der entsprechende #include vor der verwendenden Klassendeklaration kommen. Im Grossen und Ganzen wars das auch schon. Der eigentliche Knackpunkt am Ganzen liegt ganz woanders: Wie komme ich zu einer sinnvollen Aufteilung in Module? Manchmal ist das ganz einfach und naheliegend. Manchmal hat man mehrere Möglichkeiten, die sich anbieten und man muss eine auswählen und manchmal bietet sich zunächst scheinbar überhaupt nichts an. Ach muss man des öfteren eine künstliche Grenze einziehen. Gesucht ist die goldene Mitte zwischen "Die Modularisierung ist viel zu grob und bringt so gut wie gar nichts" und "Die Modularisierung ist viel zu fein und verschleiert und verkompliziert nur alles" Da liegt der Knackpunkt und das kann dir auch kein Buch beibringen. Am Anfang liegt man des öfteren schon mal daneben. Dann darf man aber auch keine Scheu haben, die Modularisierung noch mal zu überdenken und zu überarbeiten und zu sehen, ob man mit einer anderen Aufteilung die festgestellten Probleme besser in den Griff kriegt. Nichts ist so tödlich, wie die Neigung von Einsteigern, die Programmteile die sie schon haben als "von Gott gegeben und daher unveränderbar" anzusehen. Genausowenig wie dir ein Buch beibringen kann, ein berühmter Maler oder Komponist zu werden, genausowenig kann dir ein Buch die Erfahrung geben, wie man Modularisierung machen kann. Es gibt Daumenregeln, aber es gibt kein Kochrezept, dem man einfach nur folgen muss und dann ist alles gut.
Also... Das was Klaus schreibt hab ich soweit verstanden. Die einzelnen Bereiche des Programmes kommen in verschiedene .c Dateien rein, das was für alle gemeinsam gebraucht wird kommt in eine .h, die dann in all die Module includiert wird. Nur, wie mache ich das dann, daß mir all die verschiedenen .c dateien jetzt zu einem Programm zusammenkompiliert werden? Ich sollte vielleicht dazu sagen, daß ich mit Eclipse und GCC unter Linux arbeite... Danke schon mal für die ausführlichen Antworten
hubert schrieb: > Also... Das was Klaus schreibt hab ich soweit verstanden. Die einzelnen > Bereiche des Programmes kommen in verschiedene .c Dateien rein, das was > für alle gemeinsam gebraucht wird kommt in eine .h, die dann in all die > Module includiert wird. Jein. Bei kleineren/mittleren Projekten kann man es so machen. Es ist aber oft ein Zeichen von Planlosigkeit... Meist läuft es auf folgende Regeln hinaus: - Das gesamte Programm besteht aus verschiedenen Modulen, die entweder unabhängig voneinander bestehen, oder teilweise aufeinander aufbauen. Ein Modul könnte z.B. sein: * alles was mit Datenbanken zu tun hat, * alle Hilfsfunktionen zur Matrizenrechnung, * alles für Finite Elemente, ... Man kann sein Programm also senkrecht unterteilen (Datenbanken haben nicht mit linearer Algebra zu tun, die beiden kennen sich also nicht) oder waagrecht in verschiedene Schichten (Finite Elemente benötigen ein Modul zur linearen Algebra, wird aber wiederum vom Hauptprogramm benötigt). Das Ganze kann man sich schön als Bild von Hierarchien malen nach verschiedenen Regeln. Die Aufteilung in Module ist natürlich bis zu einem gewissen Grad willkürlich, aber je nach Problem gibt es sinnvolle oder dämliche Varianten. Zu jedem Modul gibt es eine .h, also z.B. eine linearealgebra.h, eine fem.h, eine db,h und so weiter. Da kommen jeweils Typdefinitonen rein, sowie Deklarationen von globalen Daten und Funktionen. Diese .h wird dann eingerahmt von:
1 | // Kommentar blabla .. von wem warum weshalb Geschichte...
|
2 | #ifndef _FEM_H_
|
3 | #define _FEM_H_
|
4 | #include <alles> |
5 | #include <was> |
6 | #include <modul> |
7 | #include <so braucht...> |
8 | ... alle Typdefinitionen, alle Deklarationen... |
9 | #endif // _FEM_H_
|
- Falls es daneben noch Definitionen gibt, dann packt man diese in eine .c gleichen Namens, also linearealgebra.c, fem.c, db.c. Die .c #includet am besten auch ihre zugehörige .h. Dadurch fallen Abweichungen zwischen Deklaration und Definition schnell durch Compilerfehler auf. Die .c und .h treten also meistens paarweise auf. > > Nur, wie mache ich das dann, daß mir all die verschiedenen .c dateien > jetzt zu einem Programm zusammenkompiliert werden? > > Ich sollte vielleicht dazu sagen, daß ich mit Eclipse und GCC unter > Linux arbeite... Ich nehme nicht Eclipse, aber da wird es irgendeine Art von Projektverwaltung geben, wo man die .c einträgt für jedes Projekt.
PS: Bei C++ ist das alles gleich, nur halt *.cpp statt .c. Außerdem wie bereits oben erwähnt kommen bei C++ alle Definitionen von inline-Funktionen/Methoden auch indie .h, nicht in die .cpp.
Das ist jetzt gut verständlich. Zur Sicherheit: Hab ich das richtig verstanden? Wenn Definitionen zu den Deklarationen dazukommen (Funktions- oder bei C++ Klassendefinitionen) und ich schreib sie in eine extra .c oder .cpp dann includiere ich das .c oder .cpp in den header rein. Muß ich dieses include dann am Ende der Headerdatei reinschreiben, so daß sie nach den Definitionen kommt? Oder ist das egal?
hubert schrieb: > Das ist jetzt gut verständlich. > > Zur Sicherheit: Hab ich das richtig verstanden? Wenn Definitionen zu den > Deklarationen dazukommen (Funktions- oder bei C++ Klassendefinitionen) > und ich schreib sie in eine extra .c oder .cpp Soweit sie halt thematisch zusammenpassen, man muß nicht für jeden Pillepallekram eine eigene Datei aufmachen. > dann includiere ich das > .c oder .cpp in den header rein. Nein!! Was habe ich da angerichtet! Eine .c oder .cpp wird (fast) nie irgendwo mit #include eingebunden! Bei einer IDE werden die einzelnen .c und .cpp von der Projektverwaltung zusammengeschraubt. Unter der Haube passiert dann das gleiche wie bei manuellem Übersetzen oder wie bei mir mit make: Jede .c oder .cpp wird einzeln kompiliert vom Compiler, dabei werden die jeweils mit #include angegebenen .h eingebunden. Dabei entsteht aus jeder .c und jeder .cpp je eine Objektdatei (unter Linux .o, unter Windows .OBJ). Anschließend wird der Linker angeworfen. Der packt alle .o bzw. .OBJ und die nötigen Bibliotheken und klebt das alles zu einem ausführbaren Programm zusammen. In deinen .c und .cpp stehen nur #includes für die Headerdateien (.h, bzw. die System-Header bei C++ ohne .h dran, wie bei #include <iostream>). Wenn du eine .c oder .cpp mit #include einbindest, hast du mit 99.9-prozentiger Sicherheit etwas nicht verstanden. Du schreibst deine .h (siehe oben). Du schreibst deine .c oder .cpp, darin stehen #include für die .h. Dann sagst du deinem Eclipse oder wem auch immer, welche .c kompiliert werden müssen (und damit implizit, welche Objektdateien später gelinkt werden müssen). Das wars.
Langsam wird das Bild noch klarer. So wie Du das jetzt beschreibst hab ich das in der Ausführlichkeit noch nirgends gelesen. Anscheinend ist das ein Thema, das unter ernsthaften Programmierern von Mund zu Ohr weitergegeben wird und das kaum einem Lehrbuch mit seinen <100-Zeilen-Beispielen wirklich drinsteht oder in den Grundlehrgängen geschult wird. Scheint so was wie der Sprung von Lehrgangstheorie zur harten Alltagspraxis zu sein.
hubert schrieb: > Langsam wird das Bild noch klarer. So wie Du das jetzt beschreibst hab > ich das in der Ausführlichkeit noch nirgends gelesen. Anscheinend ist > das ein Thema, das unter ernsthaften Programmierern von Mund zu Ohr > weitergegeben wird wenn du gut aufgepasst hast, dann ist dir vielleicht aufgefallen, dass der exakte Meschanismus, wie man seiner IDE mitteilt, welche Einzelteile alle zum kompletten Projekt gehören, von der IDE selber abhängt. Im Extremfall braucht man gar keine IDE Das Projekt bestehe aus * main.c dem Hauptprogramm, welches linear Algebra macht * linalg.c da drinnen sind alle Funktionen, die sich um lineare Algebra drehen dann wirft man seine Command line an und * compiliert main.c einzeln, zb
1 | > cc main.c /OUTPUT=main.o |
2 | CC: compiling main.c .... done |
3 | 0 errors, 0 warnings |
4 | > |
* compiliert linalg.c einzeln, zb
1 | > cc linalg.c /OUTPUT=linalg.o |
2 | CC: compiling linalg.c .... done |
3 | 0 errors, 0 warnings |
4 | > |
* linkt die beiden Einzelteile zum kompletten Programm zusammen, zb
1 | > link main.o linalg.o /OUTPUT=main.exe |
2 | Linkage Editor V 5.8: linking |
3 | * main.o |
4 | * linalg.o |
5 | * default system library |
6 | -> program created in 'main.exe' |
7 | 0 errors, 0 warnings |
8 | > |
und erhält so das fertige Programm main.exe, welches man ausführen kann. Mit einer IDE (Integrated Development Environment) ist das deutlich einfacher: Man sagt der IDE: zu meinem Projekt gehören main.c und linalg.c und die IDE kümmert sich darum, dass unter der Haube genau die gleichen 3 Schritte ausgeführt werden, wie man sie selbst auch hätte händisch machen können. Nur: Wie genau man der IDE mitteilt, was alles zum Projekt dazugehört steht im Handbuch der IDE und nicht in einem C-Lehrbuch.
Beim Kompilieren fehlt (zumindest wenn man den gcc nimmt) jeweils noch die Option -c, damit nur kompiliert wird und nicht gleich gelinkt, und die Option, die die Ausgabedatei benennt, ist -o statt /OUTPUT, zudem wird der gcc auch gleich zum Linken verwendet und die Ausgabedateien enden üblicherweise nicht auf .exe. Sonst ist aber fast alles gleich :-)
1 | gcc -c main.c -o main.o |
2 | ... |
3 | gcc -c linalg.c -o linalg.o |
4 | ... |
5 | gcc main.o linalg.o -o main |
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.