Hallo zusammen, gerade bin ich dabei einen bestehenden Programmcode in die Programmiersprache C umzuschreiben. Im konkreten geht es aber darum, dass ich mehrere Headerdateien in mein Hauptprogramm einbinde. Eine dieser Dateien führt zu einem Linkerfehler. Der Header wird als letztes eingebunden. Binde ich ihn als erstes ein, verschwindet der Linkerfehler und alles läuft problemlos. Bei dem Fehler an sich handelt es sich um die Doppeldefinition einer Variable. Diese Variable ist in der Header zugehörigen .c-Datei definiert. Es handelt sich dabei um einen Zeiger auf eine Struktur, welche in der Header-Datei deklariert ist. Dieser Zeiger ist erst einmal mit NULL initialisiert. Es handelt sich also um eine "echte" Definition. Im Grunde kann ich mir natürlich vorstellen wo das Problem liegt. Das komische ist aber, dass eben diese Header-Datei in keiner anderen Datei außer eben dem Hauptprogramm inkludiert ist. Außerdem arbeite ich selbstverständlich mit Include-Guards. Eine Variable mit gleicher Benennung gibt es auch nirgendwo. Der Typ ist ja dann an dieser Stelle schon egal. Ich kann mir nur vorstellen, dass mir bestimmte Informationen fehlen um mir das Verhalten erklären zu können. Vielleicht kann sich jemand das oben beschriebene Verhalten erklären und möchte mir weiter helfen. Wenn jemand Beispielcode braucht poste ich diesen natürlich gerne. Aber aktuell denke ich, dass meine Beschreibung das Verhaltens ganz ausreichend sein sollte. Lieben Gruß Pallas
:
Bearbeitet durch User
Idealerweise soll jeder einzelne Header bewußt so gestaltet werden daß später die Reihenfolge vollkommen belanglos ist und auch Mehrfach-Include keine Probleme bereitet. Erreicht wird das in der Praxis durch folgende zwei einfache Maßnahmen: * Jeder Header hat einen Include-Guard * Jeder Header included genau all diejenigen anderen Header die notwendig sind damit er für sich allein fehlerfrei geparst werden kann. Zum Beispiel willst Du in einem Deiner Header den Datentyp uint32_t verwenden dann muss Dein Header stdint.h includen. Benutzt er noch andere Definitionen aus anderen Headern dann muß er auch diese ebenfalls includen. Wenn alle verwendeten Header das genau so machen dann funktionieren sie * jeder eigenständig für sich allein * alle zusammen in beliebiger Reihenfolge Es gab irgendwo mal einen Styleguide der NASA der das obige schön erklärt hat und diese Praxis für jeglichen Code dort im Hause zwingend vorgeschrieben hat, ich find ihn nur leider grad nicht. Ich halte mich seit Jahren für meine eigenen Sachen strikt daran und hab noch nie Probleme mit der Reihenfolge gehabt. Auch die üblichen Standard-Header die mit dem Compiler geliefert werden und die CMSIS-Header für ARM Mikrocontroller halten sich an diese Regeln.
:
Bearbeitet durch User
Ja, genau. So habe ich mir das in letzter Zeit auch erarbeitet. (Ich lerne C gerade). Trotzdem bekomme ich dieses Verhalten. Wenn jetzt niemandem so spontan eine andere Möglichkeit einfällt, habe ich bestimmt irgendwo etwas übersehen.
Daniel S. schrieb: > > Es handelt sich dabei um einen Zeiger auf eine Struktur, welche in der > Header-Datei deklariert ist. Dieser Zeiger ist erst einmal mit NULL > initialisiert. > > Es handelt sich also um eine "echte" Definition. > Das ist grundsätzlich sehr fragwürdiger Stil. Abhilfe: Mit Copy&Paste die Variablendeklaration in die passende C Deklaration umsetzen und in der Headerdatei ein extern davor setzen und die Initialisierung herausnehmen. Also: Headerdatei vorher: struct xxx *g_StructPtr = NULL; Headerdatei nachher: extern struct xxx *g_StructPtr; Quelldatei neu: struct xxx *g_StructPtr = NULL;
Daniel S. schrieb: > Bei dem Fehler an sich handelt es sich um die Doppeldefinition einer > Variable. Variablen in Headern sollen mit der Speicherklasse extern deklariert werden, das ist dann eine Vorwärtsdeklaration ähnlich eines Funktionsprototypen damit der Compiler erstmal fehlerfrei durchlaufen kann und für alle benötigten Symbole zumindest deren Deklaration kennt. Erst der Linker sucht dann später die echten Definitionen (er such in jeder gelinkten .o Datei danach) für alles was im ganzen Programm irgendwo auf diese Weise deklariert und irgendwo verwendet wurde. Du definierst also diese Variable in einer C-datei, sinnvollerweise (aber nicht zwingenderweise) in genau der C-Datei die auch zu dem betreffenden Header gehört und in den Header kommt nur die Vorwärtsdeklaration der Variable mit dem Schlüsselwort extern. Funktionsdeklarationen in Headern sind strenggenommen auch extern, nur muß man das da nicht dazuschreiben (man könnte und es würde keinen Unterschied machen) bei Funktionsdeklarationen denkt sich der Compiler das extern automatisch selbst dazu.
:
Bearbeitet durch User
Nein nein nein. :-) Im Header steht gar nichts über den Pointer. Da steht nur die Deklaration der Struktur an sich. Dieser Pointer ist eine globale Variable in der zugehörigen .c-Datei. Er wird auch nur dort gebraucht. Wirklich nur dateiintern praktisch.
Daniel S. schrieb: > Nein nein nein. :-) > Im Header steht gar nichts über den Pointer. > Da steht nur die Deklaration der Struktur an sich. Wenn allein der #include schon eine Mehrfachdefinition auslöst dann ist in mindestens einem der Header eine Definition vorhanden. Die ist da irgendwo, die musst Du suchen und finden und eliminieren! Eigentlich müsste der Compiler Dich in der Fehlermeldung schon mit der Nase draufstoßen! Vielleicht hast Du versehentlich eine .c Datei includiert, vielleicht indirekt in irgendwas anderem was Du inkludierst, folge der Kette der Inklusionen bis zum Ende. Jegliche Definition hat in einem Header erstmal grundsätzlich nichts verloren. Geduldete Ausnahmen im begründeten Einzelfall sind kleine static inline Funktionen (beachte das Schlüsselwort static!) und eventuell auch static const in solchen Fällen wo das einfach die pragmatischste Lösung ist, sollte aber die Ausnahme und nicht die Regel sein.
:
Bearbeitet durch User
Setze den Warnlevel vom Compiler auf Maximum, so dass er alle fragwürdigen Dinge meldet. Eliminiere den Grund der Warnungen. (es ist nicht der hohe Warnlevel)
Ja, das werde ich machen. Ich muss da auf jeden Fall mal genauer hinschauen. Danke für eure Hilfe.
Bernd K. schrieb: > Wenn allein der #include schon eine Mehrfachdefinition auslöst dann ist > in mindestens einem der Header eine Definition vorhanden. > > Die ist da irgendwo, die musst Du suchen und finden und eliminieren! Ein vernünftiger Compiler würde verraten, wo die Mehrfachdefinition alle stehen, so dass man sie nicht suchen muss.
Ja, daran hatte ich gar nicht gedacht. Ich benutze den gcc. Gibt es da eventuell spezielle Schalter?
Der Compiler würde schon was zielführendes melden, da die Fehlermelding aber vom linker kommt, ist die weniger aussagekräftig. Der verrät dir aber immerhin noch den Namen der Variablen, um die es geht. Damit solltest du das Problem doch schnell finden. Und zur Ausgangsfrage: Ja, die Reihenfolge spielt ein Rolle. Der Pre-Prozessor ersetzt ein #include schlicht und einfach durch den Inhalt der inkludierten Datei. Damit ergibt sich der endgültige Sourcecode, den der Compiler zu Gesicht bekommt. Wenn damit was nicht stimmt, stimmt halt was nicht. Oliver
:
Bearbeitet durch User
Poste hier: Die Warnmeldungen dazu Alle Zeilen, die in den Warnmeldungen genannt werden Alle Deklarationen und Definitionen der Variable und in welcher Datei. Das sind nur ein paar Zeilen.
Daniel S. schrieb: > Ja, daran hatte ich gar nicht gedacht. > Ich benutze den gcc. > Gibt es da eventuell spezielle Schalter? -Wall Alles warnt der aber auch nicht. Schau in die Doku.
Daniel S. schrieb: > Das komische ist aber, dass eben diese Header-Datei in keiner anderen > Datei außer eben dem Hauptprogramm inkludiert ist. Dann gehört sie aus dem Projekt entfernt und ihr Inhalt direkt in dein Hauptprogramm eingefügt. Aber: "Bei dem Fehler an sich handelt es sich um die Doppeldefinition einer Variable." In diesem Falle benenne deine Variable um, denn so etwas ist definitiv ein Programmiererfehler. Zwei Variablen gleichen Namens gehören in kein Programm. W.S.
W.S. schrieb: > Zwei Variablen gleichen Namens gehören in kein > Programm. Variablen gehören nicht in Header-Files.
Haben alle Header einen include guard? Ich tippe zu 99% dass der in einem der Header fehlt...
Ohne Code (Minimalbeispiel!) ist das alles etwas Stochern im Dunkeln.
Kommt hier noch eine Rückmeldung was es jetzt war?
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.