Forum: PC-Programmierung Darf Header Code einbinden?


von Karl-Heinz M. (schnapsglas)


Lesenswert?

Hallo!

Ich schreibe gerade mehrere kleine Progrämmchen, die vielfach die selben 
Funtionen brauchen und in verschiedenen Unterverzeichnissen sitzen. Sind 
Metaheuristiken für die Uni.

Ist das noch im Rahmen des Korrekten, wenn ich nun für die gemeinsamen 
Funktionen folgendes mache:

Der Header ../meine_libs/lib1.h enthält #include "lib1.c"

welche im selben Ordner wie der Header liegt.
Bei einem kleinen Test hat es ohne zu meckern funktionier (gcc).

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Nein, das ist Pfusch.

Sobald nämlich die Headerdatei von zwei unterschiedlichen Stellen 
eingebunden wird, wird der Code doppelt eingebunden, und das wiederum 
ergibt Linkerfehler.

von nicht "Gast" (Gast)


Lesenswert?

Hallo,

nein, das ist nicht gut so. Code darf nur in den Header, wenn es sich um 
C++ Templates handelt.

Du benutzt ja die Header Informationen um den Inhalt deiner *.c Datei in 
deiner aktuellen Datei bekannt zu machen. Den Rest erledigt der Linker 
für dich.


Grüße,

von Postix (Gast)


Lesenswert?

Wenn du keine Lust hast, deine Lib zu linken, dann mach den Include halt 
in einem deiner .c-Files. Aber das ist mit hoher Wahrscheinlichkeit 
immer noch Quatsch - aber wenigstens funktionierender Quatsch.

von Sebastian (Gast)


Lesenswert?

> Code darf nur in den Header, wenn es sich um C++ Templates handelt.
Stimmt so nicht ganz. Code darf und muss in den Header wenn es sich um 
inline-Funktionen oder -Methoden handelt. (inline Funktionen gibt es 
auch in C99). Templates sind ein Spezialfall davon - die muss man inline 
schreiben wenn man sie nicht explizit dort instanziieren will, wo man 
sie definiert.

Dieser Code ist dann aber i.d.R. nicht in einer Datei mit Endung .c - 
Die haben in einem Header normalerweise nichts verloren.

von Uhu U. (uhu)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Nein, das ist Pfusch.
>
> Sobald nämlich die Headerdatei von zwei unterschiedlichen Stellen
> eingebunden wird, wird der Code doppelt eingebunden, und das wiederum
> ergibt Linkerfehler.

So pauschal kann man das nicht sagen.

Ich hatte vor Urzeiten mal eine Latte von Funktionsaufrufen, die immer 
mit denselben konstanten Parametern, aber verschiedenen Funktionen 
aufzurufen waren.

Ich habe das dann so gelöst, daß ich die Aufrufe mit einem 
Fantasie-Funktionsnamen in eine Datei geschrieben und diese Datei dann 
includet habe. Vor dem jeweiligen include stand ein #define, das den 
Fantasienamen auf den richtigen Funktionsnamen umdefiniert hat und 
hinten dran ein #undef. Das Ganze stand im Rumpf einer 
Funktionsdefinition und definierte selbst natürlich nichts global 
sichtbares.

Das sah zwar nicht so wahnsinnig schön aus, hatte aber den unschätzbaren 
Vorteil, daß der ganze Mist nur einmal gepflegt werden mußte und um das 
Konstrukt von den üblichen Header-Dateien abzuheben, hieß es auch nicht 
.h

Von Generatoren, wie lex, yacc, bison etc. wird auch kein schönerer Code 
produziert, aber dort mault keiner rum, das sei "Pfusch".

von Timmo H. (masterfx)


Lesenswert?

Also wenn man sich z.B. die Sourcen von AeroQuad ansieht: 
https://code.google.com/p/aeroquad/source/browse/#svn%2Ftrunk%2FAeroQuad%2FAeroQuad
dann wird man schnell merken warum Code in Header-Dateien nicht 
unbedingt zur Übersichtlichkeit beiträgt.
In Header-Files gehören nur defines, Prototypen etc. aber keine 
kompletten Funktionen. In Header-Dateien erwartet einfach niemand, dass 
dort komplette Funktionen stehen, weil sie dort einfach nicht hin 
gehören.
Header-Dateien bilden/definieren die Schnittstelle zwischen einzelnen 
Funktionseinheiten, aber die Implementierung (also die Funktionen 
selbst) gehören in die c/cpp-Datei. Ansonsten könnte man ja auch nicht 
richtig mit (vorkompilierten) libraries etc. arbeiten.

von Rene H. (Gast)


Lesenswert?

Timmo H. schrieb:
> In Header-Files gehören nur defines, Prototypen etc. aber keine
> kompletten Funktionen. In Header-Dateien erwartet einfach niemand, dass
> dort komplette Funktionen stehen, weil sie dort einfach nicht hin
> gehören.

inline spricht dagegen.

Klar "darf" man c files in die Header-Files einbinden, dem cpp ist das 
Wurscht. Nur ist es reiner Pfusch, wie Rufus schon sagte.

Rufus Τ. Firefly schrieb:
> Sobald nämlich die Headerdatei von zwei unterschiedlichen Stellen
> eingebunden wird, wird der Code doppelt eingebunden, und das wiederum
> ergibt Linkerfehler.

Das würde sich mit ifdefs unterbinden lassen.

Grüsse,
René

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Rene H. schrieb:
> Das würde sich mit ifdefs unterbinden lassen.

Nein. Deine "include guards" funktionieren nur innerhalb einer 
"translation unit", Programme bestehen aber üblicherweise aus mehreren 
davon. Und somit wäre der betreffende Code mit seinen Symbolen in 
jeder "translation unit" enthalten, und der Linker bekommt diese 
Symbole entsprechend mehrfach zu sehen.

gcc enthält die unappetitliche Möglichkeit, mehrfachdefinierte Variablen 
zu einer zusammenzufassen (was den Fehler kaschiert, 
Variablendefinitionen in Headerdateien unterzubringen), aber 
glücklicherweise lässt sich das abstellen.

von Uhu U. (uhu)


Lesenswert?

Timmo H. schrieb:
> In Header-Dateien erwartet einfach niemand, dass
> dort komplette Funktionen stehen, weil sie dort einfach nicht hin
> gehören.

Nenn sie anders, als .h und das Problem ist keins mehr...

> In Header-Files gehören nur defines, Prototypen etc. aber keine
> kompletten Funktionen.

Brave Kinder popeln nicht ;-)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Uhu Uhuhu schrieb:
> Nenn sie anders, als .h und das Problem ist keins mehr...

Nein. Augenverschließen steigert nicht die Unsichtbarkeit.

von Bunda (Gast)


Lesenswert?

Zu den inlines hat hier noch keiner eine Lösung gesagt wie es anderst 
gehen soll als den Code IN die .h zu schreiben.

von R. M. (rmax)


Lesenswert?

Die inlines sind doch gerade die Ausnahme von der Regel "kein Code in 
Header-Dateien", von daher kann und soll es da nicht anders gehen.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Um die Anzahl der Ausnahmen zu reduzieren, würde ich einfach die Regel
anders formulieren:
1
In Header-Files kommt nichts, was Code- oder Datenbytes im Object-File
2
erzeugt.

Deklarationen, Templates, Inline-Funktionen und Makro-Definitonen
erzeugen keine Bytes, also dürfen sie in die Header-Files.

von Uhu U. (uhu)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Nein. Augenverschließen steigert nicht die Unsichtbarkeit.

Na ja, Konstruktionen wie
1
#define XMACRO(x, y, z) DoSomething(y)
2
   #include "generatormacros.m"
3
#undef XMACRO
waren bei mir immer so auffällig, daß sie nicht übersehen wurden - ganz 
im Gegensatz zu so manch anderer "koscherer" Konstruktion...

Mit Macros kann man natürlich viel Unsinn machen - wie mit jedem 
Küchenmesser auch. Aber wenn man keine hat, wie z.B. bei C#, dann können 
gewisse Aktionen doch zu ziemlich stupiden Schreibaufgaben entarten.

Die Sprache läßt jedenfalls fast alles zu, so lange die 
Blockschachtelungstiefe durch den include-File nicht verändert wird.

von cppler (Gast)


Lesenswert?

Halte Dich einfach an die Standards und bedenke das die Wartbarkeit 
eines Programms von seiner Struktur abhängt.
Wenn dann irgendwo was klemmt und der Debugger auf einmal im Headerfile 
nichts findet kommt die große Freude auf.
Die Frage ist halt was erreicht werden soll ?
Willst Du sowas haben:
1
#if SYSTEM_1
2
   # include "system_1.h"
3
#elif SYSTEM_2
4
   # include "system_2.h"
5
#elif SYSTEM_3
6
   ...
7
#endif
Wobei bei jedem header das passende c dazugelinkt wird.
Das makefile bietet da allerdings wesentlich mächtigere Möglichkeiten.
Und was halt verwundert, warum mußt Du die Funktion mehrfach einbinden ?
Soweit ich Dich verstanden habe mußt Du mehrere Programme mit der 
gleichen Bibliothek erstellen.
Was macht denn:
1
#include <stdio.h>
Für Dich wäre es doch sinnvoller:
1
#include "meinpfad/meinheader.h"
in jedes Programm einzubringen oder verstehe ich gerade Dein Problem 
nicht ?
Achso jetzt kapiere ich gerade den "Faulheitsfaktor" :-P
Schreibe Dir ein Shellmakro das die makefiles anpaßt und gut ist ...

von Rene H. (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Rene H. schrieb:
>> Das würde sich mit ifdefs unterbinden lassen.
>
> Nein. Deine "include guards" funktionieren nur innerhalb einer
> "translation unit", Programme bestehen aber üblicherweise aus mehreren
> davon. Und somit wäre der betreffende Code mit seinen Symbolen in
> jeder "translation unit" enthalten, und der Linker bekommt diese
> Symbole entsprechend mehrfach zu sehen.
>
> gcc enthält die unappetitliche Möglichkeit, mehrfachdefinierte Variablen
> zu einer zusammenzufassen (was den Fehler kaschiert,
> Variablendefinitionen in Headerdateien unterzubringen), aber
> glücklicherweise lässt sich das abstellen.

Nö. Der cpp bindet das exakt einmal ein. Wenn es an der richtigen Stelle 
steht funktioniert das.
Wenn Du mit "translation units" libraries meinst, ja, dann fällt der 
Linker auf die Schnauze. Ein Symbol darf nun mal nur einmal vorkommen. 
Aber das war nicht die Fragestellung.

Ohne Libs funzt das, auch wenn es nicht sauber ist.

Die Konventionen sind gegeben.

Grüsse,
René

von Uhu U. (uhu)


Lesenswert?

Rene H. schrieb:
> Ohne Libs funzt das, auch wenn es nicht sauber ist.

Das sind Common-Blocks. Wenn mehrere mit gleichem Namen gefunden werden, 
wird jeweils die größte Version eingebunden. Fortran benutzt das seit 
Urzeiten.

Es ist halt wie fast immer: Wer nicht weiß, was er tut, kann nicht damit 
rechnen, daß das dabei herauskommt, was er sich erträumt und dieses 
Geschwätz von "Sauberkeit" bedient sich seit Jahrzehnten immer mal 
wieder anderer Features, die verteufelt werden.

Invariante ist aber stets, daß diejenigen, die sich seiner bedienen, 
bestenfalls Halbwisser sind...

von Rene H. (Gast)


Lesenswert?

Uhu Uhuhu schrieb:
> Rene H. schrieb:
>> Ohne Libs funzt das, auch wenn es nicht sauber ist.
>
> Das sind Common-Blocks. Wenn mehrere mit gleichem Namen gefunden werden,
> wird jeweils die größte Version eingebunden. Fortran benutzt das seit
> Urzeiten.
>
> Es ist halt wie fast immer: Wer nicht weiß, was er tut, kann nicht damit
> rechnen, daß das dabei herauskommt, was er sich erträumt und dieses
> Geschwätz von "Sauberkeit" bedient sich seit Jahrzehnten immer mal
> wieder anderer Features, die verteufelt werden.
>
> Invariante ist aber stets, daß diejenigen, die sich seiner bedienen,
> bestenfalls Halbwisser sind...

Ich weiss was ich tue. Was willst Du mir genau sagen?

Grüsse,
René

von Stefan R. (srand)


Lesenswert?

Rene H. schrieb:
> Wenn Du mit "translation units" libraries meinst, ja, dann fällt der

Wenn du nicht weißt, was translation units sind, dann lern doch erstmal, 
bevor du hier im Brustton der Überzeugung Behauptungen aufstellst.

> Ohne Libs funzt das, auch wenn es nicht sauber ist.

Nein, mit "Libs" hat das nichts zu tun.

von Rene H. (Gast)


Lesenswert?

Stefan Rand schrieb:
> Rene H. schrieb:
>> Wenn Du mit "translation units" libraries meinst, ja, dann fällt der
>
> Wenn du nicht weißt, was translation units sind, dann lern doch erstmal,
> bevor du hier im Brustton der Überzeugung Behauptungen aufstellst.
>
>> Ohne Libs funzt das, auch wenn es nicht sauber ist.
>
> Nein, mit "Libs" hat das nichts zu tun.

Gut ja, damit hast Du recht.

Grüsse,
René

von Translation Unit (Gast)


Lesenswert?

Stefan Rand (srand) schrieb:

Rene H. schrieb:
>> Wenn Du mit "translation units" libraries meinst, ja, dann fällt der

> Wenn du nicht weißt, was translation units sind, dann lern doch erstmal,
> bevor du hier im Brustton der Überzeugung Behauptungen aufstellst.

Dann erklärs ihm doch einfach und labere nicht von oben herab.

von Rene H. (Gast)


Lesenswert?

Translation Unit schrieb:
> Stefan Rand (srand) schrieb:
>
> Rene H. schrieb:
>>> Wenn Du mit "translation units" libraries meinst, ja, dann fällt der
>
>> Wenn du nicht weißt, was translation units sind, dann lern doch erstmal,
>> bevor du hier im Brustton der Überzeugung Behauptungen aufstellst.
>
> Dann erklärs ihm doch einfach und labere nicht von oben herab.

Danke Dir :-).

Die Rüge habe ich allerdings  wohl verdient. Ich hab das gegoogelt. Das 
ändert allerdings an meiner Aussage lediglich das keine libs gemeint 
sind sondern eben objs.

Und ja, auch wenn ich seit 24 Jahren Software schreibe, diesen Ausdruck 
kannte ich nicht. Man lernt nie aus.



Grüsse,
René

von Rene H. (Gast)


Lesenswert?

Aber apropos labern,

@Stefan Rand, weisst Du denn was "translation units" sind? Wenn ja, dann 
verwirrt Deine Aussage, dass es nichts mit libs zu tun hat.

Grüsse,
René

PS: bei Stackoverflow Thema: According to standard C++: A translation 
unit is the basic unit of compilation in C++. It consists of the 
contents of a single source file, plus the contents of any header files 
directly or indirectly included by it, minus those lines that were 
ignored using conditional preprocessing statements.

A single translation unit can be compiled into an object file, library, 
or executable program.

The notion of a translation unit is most often mentioned in the contexts 
of the One Definition Rule, and templates.

von Stefan R. (srand)


Lesenswert?

Rene H. schrieb:

> @Stefan Rand, weisst Du denn was "translation units" sind? Wenn ja, dann

Natürlich.

> verwirrt Deine Aussage, dass es nichts mit libs zu tun hat.

Inwiefern?

von Rene H. (Gast)


Lesenswert?

> A single translation unit can be compiled into an object file, library,
> or executable program.

Grüsse,
René

von Stefan R. (srand)


Lesenswert?

Ja und? Genauso kannst du behaupten, das ASCII oder elektrischer Strom 
etwas mit Libraries zu tun haben.

von Rene H. (Gast)


Lesenswert?

Stefan Rand schrieb:
> Ja und? Genauso kannst du behaupten, das ASCII oder elektrischer Strom
> etwas mit Libraries zu tun haben.

Ich habe kein Problem damit, einzugestehen das ich falsch lag. Nach 
Deinem dafürhalten tat ich das.
Trotzdem wäre ich froh, wenn Du mir erklärst, was falsch ist. Ich habe 
in meinem Post ja bereits deutlich gemacht, dass ich nicht weiss was 
•translation units" sind.
Vielleicht findest Du die Zeit mir das zu erklären.

Grüsse,
René

von Stefan R. (srand)


Lesenswert?

Was ist eigentlich dein Problem mit mir?

Du schreibst "Wenn Du mit "translation units" libraries meinst".

Ich weise darauf hin, daß die beiden Begriffe keine Synonyme sind, 
sondern unabhängig voneinander.

Was soll ich dir noch erklären? Sags mir, ich versteh nicht, was du 
willst.

von Translation Unit (Gast)


Lesenswert?

Stefan Rand (srand) schrieb:

> Was soll ich dir noch erklären? Sags mir, ich versteh nicht, was du
> willst.

Mein Gott, Mr. "Herr Allwissend" Stefan Rand (srand), dann erkläre ihm 
doch endlich den Begriff "Translation Unit". Das sollte doch einem der 
sich so forsch hier in die Diskussion einschaltet anfürsich leicht 
fallen oder etwa doch nicht?

von Stefan R. (srand)


Lesenswert?

Zur Hand habe ich gerade nur C, nicht C++:

A source file together with all the headers and source files included 
via the preprocessing directive #include is known as a preprocessing 
translation unit. After preprocessing, a preprocessing translation unit 
is called a translation unit.

Weiter unten heißt es dann

In the set of translation units and libraries that constitutes an entire 
program [...]


Und was hilft das jetzt?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?


von Rene H. (Gast)


Lesenswert?

Translation Unit schrieb:
> Mein Gott, Mr. "Herr Allwissend" Stefan Rand (srand), dann erkläre ihm
> doch endlich den Begriff "Translation Unit".

Nochmals Danke für die Hilfe. :) Die war wohl nötig.

Stefan Rand schrieb:
> Und was hilft das jetzt?

Das ich verstehen kann was Du mit:

Stefan Rand schrieb:
> Nein, mit "Libs" hat das nichts zu tun.

exakt meinst. Jetzt verstehe ich die Begrifflichkeit dank Deiner 
Erklärung. Wie gesagt, ich kannte den Begriff nicht und auch meine 
Kollegen, egal ob Jung oder Alt konnten mit dem nichts anfangen. Bevor 
Du ausholen willst, nein, das sind mitnichten Pfeifen.

Stefan Rand schrieb:
> Was ist eigentlich dein Problem mit mir?


Mit Dir habe ich kein Problem, weshalb auch. Man kennt sich ja nicht.

Dennoch, Danke für die Erklärung der Begrifflichkeit.

Ich kann es trotzdem nicht lassen (sorry, Rufus, wenn es gegen die Regel 
ist, dann lösch das Posting):

Der Hochmut der Kleinen besteht darin, immer, der Großen, nie von sich 
selbst zu sprechen.

[Voltaire]

Grüsse,
René

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
Noch kein Account? Hier anmelden.