Deklaration und Implementierung nicht immer trennen?

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
Chris
Beiträge: 7
Registriert: Sa Okt 13, 2012 6:48 am

Deklaration und Implementierung nicht immer trennen?

Beitrag von Chris » Mi Okt 17, 2012 6:43 am

Guten Morgen,

mich beschäftigt gerade die Frage, ob es immer sinnvoll ist die Deklaration in Headerdateien und dessen Implementierung in .c .cpp immer zu trennen?

Ich habe mal gehört, dass dies Sinn macht wenn man eine Lib schreibt und nur die Prototypen dem Kunden zur Verfügung zu stellen möchte. Oder wenn man wirklich ganz große Projekte hat, um dort dann die Zeit für die Kompilierung zu verringern. Ich habe aber auch irgendwas im Hinterkopf, in der Art von: Der Compiler kann viel besser optimieren wenn er auch gleich die Implementierung vorgesetzt bekommt, da er später nicht mehr weiß was in einer anderen Objektdatei gemacht/gebraucht wurde.

Noch ein Grund für diese Aufteilung war ja auch die begrenzten Ressourcen früherer Rechner, aber heute kann man schon so einiges im Arbeitsspeicher halten, was mich noch neugieriger auf eine Antwort macht.

Also, wann ist es heute nicht mehr sinnvoll, im Sinne der Optimierung, Header und Implementierung zu trennen?

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: Deklaration und Implementierung nicht immer trennen?

Beitrag von fat-lobyte » Mi Okt 17, 2012 11:34 am

Da gibts einige Philosophien und Aspekte.

1) Inlining. Oft ist es effektiver, wenn der Compiler den Funktionsaufruf wegoptimiert und den Funktionscode direkt an die Stelle des Aufrufs kopiert. Rein theoretisch würde es sich empfehlen einfach alles in den Header zu packen, ABER das sollte man aus den Gründen unten nicht tun. Außerdem können moderne Compiler (neue GCC, VisualC++) selbst aus kompilierten Dateien den Code rausholen und noch inlinen. Das nennt sich "Whole Program Optimization", dauert schweinelang, eliminiert aber die Notwendigkeit zu viel Code in den Header zu packen.

2) "Ease of Use": Wenn du deinen gesamten Code in den Header packst, wie es z.B. die meisten Boost-Bibliotheken machen, dann braucht der Benutzer keine bibliotheken installieren und irgendwelche spezialoptionen zum linken aufzurufen.

3) "Kapselung": Wenn man proprietäre Bibliotheken schreibt, muss man wirklich aufpassen dass man nicht zuviel im Header herzeigt.
Das beschränkt sich aber nicht nur auf "Geheimhaltung": ich empfinde es als guten Programmierstil, wenn die Teilmodule eines Programms/Bibliothek möglichst wenig voneinander wissen und dass die Schnittstellen klein und Wohldefiniert sind. Deswegen sollte man auch aus Gründen der Selbstdisziplin möglichst wenig in Header packen.

4) Binärkompatibilität:
Wenn man mal etwas weiter mit seinem Projekt ist, sollte man nicht nur auf die API schauen, sondern man sollte sich auch gedanken über die ABI (App. Binary Compatibility) machen. Die sollte nach Möglichkeit so aussehen, dass bei einem Update der Library nicht das gesamte Endprogramm neu kompiliert werden muss. Was das betrifft sollte man so wenig Code wie möglich in die Header packen, denn Code ändert sich meist häufiger als Deklarationen.

5) Kompilierzeit:
Selbstverständlich steigt die Kompilierzeit, wenn Header mehrmals kompiliert werden müssen. Dieses Problem wird allerdings durch "Precompiled Headers" gelöst, und selbst ohne Precompiled Headers ist es nicht so gravierend, dass ich meinen Programmierstil ändern müsste.


Aus den Gründen 3)-5) habe ich mich in meinen Projekten dazu entschieden möglichst wenig Code/Deklarationen im Header zu lassen, unter anderem auch damit die Header- und Codeabhängigkeiten möglichst einfach sind.
Haters gonna hate, potatoes gonna potate.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Deklaration und Implementierung nicht immer trennen?

Beitrag von Xin » Mi Okt 17, 2012 11:37 am

Chris hat geschrieben:Guten Morgen,

mich beschäftigt gerade die Frage, ob es immer sinnvoll ist die Deklaration in Headerdateien und dessen Implementierung in .c .cpp immer zu trennen?
Sätze, die die Worte "immer" oder "nie" enthalten sind nie sinnvoll und immer falsch.
Chris hat geschrieben:Ich habe mal gehört, dass dies Sinn macht wenn man eine Lib schreibt und nur die Prototypen dem Kunden zur Verfügung zu stellen möchte. Oder wenn man wirklich ganz große Projekte hat, um dort dann die Zeit für die Kompilierung zu verringern. Ich habe aber auch irgendwas im Hinterkopf, in der Art von: Der Compiler kann viel besser optimieren wenn er auch gleich die Implementierung vorgesetzt bekommt, da er später nicht mehr weiß was in einer anderen Objektdatei gemacht/gebraucht wurde.
Sogenannte 'inline'-Funktionen können nur inline kompiliert werden, wenn sie dem Compiler bei der Kompilierung auch bekannt sind. Sie müssen im Header stehen.
Chris hat geschrieben:Noch ein Grund für diese Aufteilung war ja auch die begrenzten Ressourcen früherer Rechner, aber heute kann man schon so einiges im Arbeitsspeicher halten, was mich noch neugieriger auf eine Antwort macht.
Ein Phasencompiler arbeitet so nicht. Er lädt pro Datei alle Dateien ein, kompiliert, vergisst alles.
Gutes Handling von Headerdateien, beschleunigt heute, wie damals deutlich den Kompiliervorgang.
Chris hat geschrieben:Also, wann ist es heute nicht mehr sinnvoll, im Sinne der Optimierung, Header und Implementierung zu trennen?
Es ist immernoch sinnvoll. Schon alleine daher, da Objekte sich teilweise kreuzreferenzieren: Objekt A braucht B und B braucht A. Die Implementierung von A kann also nur funktionieren, wenn B deklariert ist, B kann aber nicht deklariert werden, weil automatisch die Implementation definiert würde. Die Implementation kann aber nicht definiert werden, weil man A dafür deklariert haben müsste. Das versucht der Compiler ja auch gerade, aber soweit ist er eben noch nicht. Also scheitert die Deklaration von B, woraufhin Deklaration und Definition von A scheitert.

Man kann das tricksen. Manchmal muss man das. Mit schöner Programmierung hat das in C++ nichts mehr zu tun. Trennt man Deklaration und Definition, passt das wieder.
Java und C# machen das automatisch, C++ hat da eine einfachere, klare Linie, da "#include" auch kein C-Konstrukt ist. "using" funktioniert hier in der Form, dass die Implementation quasi ignoriert wird, das ist ein anderes Konzept, was an dieser Stelle sicherlich praktischer ist.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Chris
Beiträge: 7
Registriert: Sa Okt 13, 2012 6:48 am

Re: Deklaration und Implementierung nicht immer trennen?

Beitrag von Chris » Mi Okt 17, 2012 1:15 pm

Danke für die Antworten, Sachen wie "Whole Program Optimization" kannte ich bis dato noch nicht. Also habe ich die Möglichkeit im Nachhinein dem Compiler wirklich mein ganzes Programm zur Optimierung zu geben. Die anderen Gründe ,gegen ein Programm im Ganzen, klingen auch logisch.

Antworten