Ich habe noch nie den Grund für die Trennung zwischen source files und header files wirklich verstanden. Vorneweg: ich bin alles andere als ein gelernter Programmierer, daher bitte ich um Nachsicht für diese Proletenfrage. Aktuell arbeite ich mit dem USB-Framework von Microchip und wundere mich erneut. In den header files sind lediglich die Funktionen und Prozeduren aufgelistet, welche in den gleichnamigen sourcefiles dann enthalten sind. Auf diese Art müssen immer 2 Dateien mit gleichem Namen (einmal .c und einmal .h) parallel gepflegt werden. Warum kann man nicht einfach nur die sourcefiles einbinden, ohne headerfiles? Wenn es der Lesbarkeit wegen ist, kann man doch einfach in den sourcefiles zu beginn alle Prototypen auflisten. Was ist der Grund für die strenge Trennung der Protoypen auf die header files und den Code in den sourcefiles? Danke Leute vorab für die Erleuchtung, die mir noch gänzlich fehlt.
kauf dir ein c/c++ buch und lies es dir durch... es hat mit dem ganzen build prozess zu tun: erst wird compiliert dann werden die objektdateien zum programm gelinkt. zu dem compilier zeitpunkt "versprechen" die header files die existens der funktionen/methoden, da der compiler nur jeweils 1ne sourcefile kennt. in der zeit von interpretersprachen ala. java, python, php ist ein wenig sinnlos..da es auch anderst gehen könnte...
...weil "C" niemals als ernsthafte Programmiersprache konstruiert wurde. Das ganze war ein Scherz von zwei Studenten, welcher auf einem möglichst blödsinnigem Konzept, der Verwendung überflüssiger Zeichen, hirnrissiger syntaktischer Regeln u.s.w. basierte - sprich: alles falsch machen, was man falsch machen kann - und sich dann leider verselbstständigte, weil einige langhaarige, lichtscheue, pickelige Kellerkinder (die sich auch versuchen mit Aluminiumfolie auf dem Kopf vor Strahlenbeeinflussung durch Geheimdienste zu schützen)für bahre Münze genommen wurde. Ein dysfunktionales "Werkzeug" von Deppen für Deppen.
> Aktuell arbeite ich mit dem USB-Framework von Microchip und wundere mich > erneut. In den header files sind lediglich die Funktionen und Prozeduren > aufgelistet, welche in den gleichnamigen sourcefiles dann enthalten > sind. So solls sein :-) > Auf diese Art müssen immer 2 Dateien mit gleichem Namen (einmal .c und > einmal .h) parallel gepflegt werden. Das vereinfacht(!) die Sache erheblich. > Warum kann man nicht einfach nur die sourcefiles einbinden, ohne > headerfiles? Dann braucht jedes(tm) Source-File alle(tm) Forward-Deklarationen aller(tm) anderen C-Files. Nicht praktikabel. > Wenn es der Lesbarkeit wegen ist, kann man doch einfach in den > sourcefiles zu beginn alle Prototypen auflisten. Das ist nicht wartbar. Siehe oben. > Was ist der Grund für die strenge Trennung der Protoypen auf die header > files und den Code in den sourcefiles? Erhebliche Vereinfachung und Information-Hiding.
Andi D. schrieb: > kauf dir ein c/c++ buch und lies es dir durch... > es hat mit dem ganzen build prozess zu tun: erst wird compiliert dann > werden die objektdateien zum programm gelinkt. > zu dem compilier zeitpunkt "versprechen" die header files die existens > der funktionen/methoden, da der compiler nur jeweils 1ne sourcefile > kennt. > > in der zeit von interpretersprachen ala. java, python, php ist ein wenig > sinnlos..da es auch anderst gehen könnte... O.k. das ist wohl der Grund. In meinen C-Anfängen hatte ich nämlich immer nur mit source-files gearbeitet: in meinem Hauptprogramm hat es z.B. so ausgesehen: #include <defs.c> /* Typen-, Variablen- und Konstantendefinitinen*/ #include <system.c> /* System- und Interruptfunktionen */ #include <tasks.c> /* Anwendungsroutinen */ und dann kam irgendwann meine main-schleife. Ich musste natürlich dafür sorgen, dass z.B. in system.c nicht auf Funktionen in tasks.c zugegriffen wurde, aber das war relativ einfach zu bewerkstelligen und von der Struktur her sehr übersichtlich. Die "Low-Level"-Funktionen also immer vor den "High-Level-Funktionen" Aber das USB-Framework ist natürlich "etwas" umfangreicher als mein früherer Proletencode und offenbar verwenden dann die einzelnen Module untereinander gegenseitig deren Funktionen, so dass meine banale Denkweise hier nicht mehr funktionieren würde, so wie es g457 meint (nicht mehr pflegbar wegen der daraus resultierenden vielen Protoypen in den einzelnen Modulen). Ich glaube aus dieser Sichtweise heraus habe ich es dann verstanden. Falls nicht, bitte nochmal aufklären, ansonsten vielen Dank an die werte Gesellschaft!
Diese Header Dateien sind nicht wirklich notwendig, sonst würden diverse andere Programmiersprachen auch nicht ohne auskommen. Die sind nur dazu da, um Anfänger zu verwirren.
Rotkohl schrieb: > in meinem Hauptprogramm hat es z.B. so ausgesehen: > #include <defs.c> /* Typen-, Variablen- und > Konstantendefinitinen*/ > #include <system.c> /* System- und Interruptfunktionen */ > #include <tasks.c> /* Anwendungsroutinen */ > und dann kam irgendwann meine main-schleife. Und genau eben dies ist aus ganz ganz vielen Gründen mehr als gefährlich. > Ich musste natürlich dafür sorgen, dass z.B. in system.c nicht auf > Funktionen in tasks.c zugegriffen wurde, aber das war relativ einfach zu > bewerkstelligen und von der Struktur her sehr übersichtlich. > Die "Low-Level"-Funktionen also immer vor den "High-Level-Funktionen" Ahja, und das ist jetzt leichter zu pflegen meinst du? In einem großen Projekt? Und wenn zwei "High-Level-Funktionen" eine "Low-Level-Funktion" benötigen, dann hagelt es sofort duplikate Definitionen. > Ich glaube aus dieser Sichtweise heraus habe ich es dann verstanden. > Falls nicht, bitte nochmal aufklären, ansonsten vielen Dank an die werte > Gesellschaft! Es hat unter anderem damit zu tun, ja.
Blaukraut schrieb: > Diese Header Dateien sind nicht wirklich notwendig, sonst würden diverse > andere Programmiersprachen auch nicht ohne auskommen. Die sind nur dazu > da, um Anfänger zu verwirren. Darum rede ich ja auch von C...
Ich muss des Öfteren Schnittstellen ändern, wodurch ich für viele Sachen die Trennung von Source und Header aufgegeben habe. Und ja, das spricht auf Softwareentwickler-Sicht nicht gerade für Qualität, da Schnittstellen sich nicht ändern sollten. Gerade aus dem Grund, weil das so nervig ist, gibt es einige Tools, die den Entwickler beim Programmieren unterstützen sollen und auch eine intelligente Funktionskopf-Anpassung ermöglichen. Oder man macht aus allen Funktionen Template-Funktionen :D
robert schrieb: > ...weil "C" niemals als ernsthafte Programmiersprache konstruiert wurde. Bisschen geschmunzelt hab ich ja. Aber fürs Lachen war die Satire dann doch wieder nicht gut genug. Nun ernsthaft: Die Header sind sozusagen der Kern des 'Wiederverwertungskonzeptes' von C/C++. Also einfach gesagt: Jemand schreibt Code mit Funktionen, die man gerne in anderen Programmen wieder benutzen möchte. Damit die Schnittstelle stimmt, muss dafür ein Prototyp deklariert werden. Nun könnte man den Prototyp natürlich 'inline' (im Source selbst) deklarieren, aber ändert man die API ('Application programming interface' und das kommt bei der über Jahre hinweg gewarteten und möglichst portablen Library immer irgendwann mal vor), kann das schrecklich in die Hose gehen, wenn die Prototypen nicht per Header genau an einer Stelle deklariert und von allen Nutzern (referenzierender Programmcode, inklusive der Implementierung!) eingebunden (per #include) werden. Der Klassiker: Datei a.c: extern char *g_bla; Datei b.c: char g_bla[] = "blabla"; Wer's noch nicht kennt: einfach mal ausprobieren, was passiert, wenn man aus a.c g_bla per printf ausgibt. Leider ist C nicht so streng wie z.B. ADA, und erlaubt den nicht auf API-Programmierung gebürsteten C-Hackern, sich massiv ins Knie zu schiessen und es jahrelang nicht zu merken. Zu dem restlichen Geunke betr. anderer Programmiersprachen bleibt nur zu sagen: Um das Problem einer Bibliotheks-API kommt keine native Compilersprache herum, und eine Interpretersprachen-Anbindung will auch erst mal geschrieben werden (dreimal darf man raten womit). Abschliessend einige Faustregeln (siehe auch C-FAQ) für eine bestmöglichst wartbare API: - Nur die Prototypen gehören in die Header, die Implementation in die .c sources (#include "bla.c" ist ver bo ten!) - Vorsicht mit globalen Variablen. Wenn möglich eine Context-Struktur verwenden und als abstraktes Handle (siehe 'anonymer struct pointer') an die API-Funktion übergeben - Library User sollten nicht direkt auf Mitglieder einer Struktur direkt zugreifen. Wenn doch: Versionskontrolle/Inkompatibilitäts-Handling nötig. Wenn man es 'richtig' macht, liefern ein C-Compiler und Linker sehr wertvolle Hinweise, die die Wartung und Portierung von Code, somit die Wiederverwertung optimal möglich machen. Wie man Headerstrukturen optimal entwirft, ist eine eigene Wissenschaft, die man oft an den FHs/Unis nicht lernt. Was ich sehr empfehlen kann, ist, einfach mal eine Portierung eines OS oder Programms auf eine andere Architektur anzugehen.
Ja, danke nochmal für die Erläuterungen. Das zeigt mir zumindest, dass meine Frage nicht gänzlich bescheuert war und diese Thematik doch breit bekannt ist. Gracias Senores!
BoeserFisch schrieb: > - Nur die Prototypen gehören in die Header, die Implementation in die > .c sources (#include "bla.c" ist ver bo ten!) Au ja, erzähl das mal ST, die genau so einen Scheiß in ihrer stdperiphlib machen. Kontakt-E-Mail-Adressen oder sowas in Headern, README oder sonstiger Dokumentation sind natürlich auch verboten. Echt jetzt, die spinnen, die Franzosen.
eines muss ich noch los werden. Hatte vor ca.2 Jahren mal für eine Abteilung eine etwas umfangreichere Lüftersteuerung in C schreiben müssen. Hat wunderbar funktioniert und ich habe es natürlich nach meiner "altbewährten" header-freien Methode wie oben beschrieben gemacht. Alles schön dokumentiert mit Flussdiagrammen und allem was dazugehört. Der Software-man dieser Abteilung hat meinen Code dann angeschaut und bemerkt, dass ich einen komischen Programmierstil habe. Er hat dann überall separate header-files daraus und dazu gemacht, das Projekt wurde m.E. dadurch erheblich unübersichtlicher. Aber ein Programmierprofi (er hatte das gelernt) braucht das offenbar so. Diese Firmware wurde bis dato zwar nie geändert aber der offizielle C-Aufbau musste eingehalten werden. Naja, damals habe ich das nicht wirklich nachvollziehen können, aber wenn ein anderer einmal so eine Software pflegen muss, dann tut er sich mit einem "Norm-Aufbau" natürlich leichter, als mit meiner sauber dokumentierten Proleten-Programmiererei (bin eher der HW- und Assembler-Fuzzi). Ich lerne ja gerne dazu.
Andi D. schrieb: > ... > zu dem compilier zeitpunkt "versprechen" die header files die existens > der funktionen/methoden, da der compiler nur jeweils 1ne sourcefile > kennt. > ... Das Konzept geht noch weiter: Die Headerfiles ermöglichen zum Beispiel erst den Einsatz von Bibliotheken (libs) und extern vorkompilierten Code aus anderen Sprachen (asm, maschinencode). Denn diese Dateien werden vom C-Kompiler ja gar nicht angefasst, sondern erst vom Linker.
An Rotkohl: Natürlich kann man das Spiel genauso ad absurdum treiben, wenn man es einfach 'so gelernt' hat und ohne Pragmatismus 'akademisch richtig' macht. Im Endeffekt will kaum einer eine riesige API mit mehr als 20 Funktionen pro Library nach aussen abbilden. Was als geschlossenes Modul gedacht ist, soll ruhig auch so bleiben, solange die Prototypen/Instanzen genau an einer Stelle existieren. Nur muss man's dann auch konsequent tun und nicht exportierte Funktionen möglichst mit "static" dekorieren. Modularer Code ist einfacher wiederzuverwerten und ev. besser zu dokumentieren (Doxygen). Aber ich würde auch kaum einen Code von Anfang an auf höchste Modularität abstrahieren (was einige C++-'Coder' wiederum tun und sich mit 'OO' ins Knie schiessen). Allerdings kann ich von einem relativ komplexen Code-Refaktoring-Projekt berichten, bei dem es drei Mannjahre gekostet hat, den Spaghetticode zu einer nutzbaren Library zu machen. Da hätte man es besser von Grund auf neugeschrieben bzw. hätte sich im Nachhinein ca. 200 k€ gespart, wenn man von Anfang an auf Wiederverwertbarkeit geachtet hätte. An Stefan: Ne Menge dicker Fische machen's falsch, mag daran liegen, dass die Ameisenarbeit oft an Leute outgesourct werden, die mit API-Programmierung wenig Erfahrung haben...
@BoeserFisch Ja, Du hast schon recht. Das Hauptproblem ist wohl, dass man auf manche Programmieraufgaben Leute wie mich loslässt, die das Programmieren nie sauber gelernt haben (so ein Semster lang Dödel-Informatik für E-Techniker ist da nich ganz der Reisser...). Dafür gibt es ja nicht umsonst jede Menge Fachleute. Aber wenn eben die Kapazitäten beschränkt sind, dann nimmt man auch Programmier-LowPerformer wie mich. Mir machts ja auch Spaß aber ich habe immer das Gefühl, es nicht wirklich gut zu machen. Und dafür bräuchte ich solche Aufgaben öfters, damit sich das Aneignen der korrekten Techniken auch wirklich lohnt.
Beitrag #5541875 wurde von einem Moderator gelöscht.
Beitrag #5541983 wurde von einem Moderator gelöscht.
Beitrag #5542038 wurde von einem Moderator gelöscht.
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.