Forum: Compiler & IDEs Doppelte Definitionen (Header Datei)


von Problemha-Bär (Gast)


Lesenswert?

Hallo

Ich bekomme durch folgende .h Datei immer diese Warnungen ausgespuckt:
1
*** W1327L: Duplicate symbol definition (fifo / _fifo)
2
*** W1327L: Duplicate symbol definition (i / _i)

Das deutet für mich auf eine doppelte Definierung von "i" und "fifo".
Die .h Datei müsste aber so stimmen oder?
1
#ifndef __fifo_h__
2
#define __fifo_h__
3
4
#include "can.h"
5
6
//Prototpen
7
void     put(CAN_struct *in);
8
int     ringindex(int i);
9
void     fifo2uart(void);
10
void     get(CAN_struct *out);
11
void     clear_fifo(void);
12
void     usartInit(void);
13
void     usart_send(uint8_t data);
14
15
// FIFO erstellen
16
#define   FIFO_MAX_ZEILE 5            // FIFO Größe
17
#define   FIFO_MAX_SPALTE 10            // 10 Byte ist ein FIFO Eintrag lang (1 CAN Frame)
18
uint8_t   fifo[FIFO_MAX_ZEILE][FIFO_MAX_SPALTE];   // MAX_ZEILE*MAX_SPALTE Einträge, pro Eintrag ein uint8_t Wert
19
uint16_t   i;
20
21
#endif



: Gesperrt durch Moderator
von schmichael (Gast)


Lesenswert?

Hallo,

in .h-Dateien sollte alles extern deklariert sein und in einer .c-Datei 
sollten die Variablen angelegt werden.
Dann kommt auch keine doppelte Deklaration zu stande.

Gruß Michael

von Joe D. (kosmonaut_pirx)


Lesenswert?

hallo,
die .h -datei stimmt solange, wie du sie nur in einer .c -datei 
einbindest.
wenn du dieses jedoch mehrmals tust, gibt's zu recht mecker, weil die 
variablen mehrfach definiert sind.

siehe dazu der unterschied zwischen deklaration und definition.

bye kosmo

von Problemha-Bär (Gast)


Lesenswert?

ich dachte, um das zu umgehen gibt es die Befehle

#ifndef
#define



?

von Problemha-Bär (Gast)


Lesenswert?

also es gibt keine Warnungen mehr wenn ich die beiden

uint8_t   fifo[FIFO_MAX_ZEILE][FIFO_MAX_SPALTE];
uint16_t   i;

in die main.c als Globale Var. lege.

Ich wollte sie aber ein bisschen trennen, da sie zum FIFO gehören.
Geht also nit anders?

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Was bitte ist daran nicht zu verstehen?

>siehe dazu der unterschied zwischen deklaration und definition.

von Stefan (Gast)


Lesenswert?

> ich dachte, um das zu umgehen gibt es die Befehle
> #ifndef
> #define

Das verhindert Probleme, wenn du die Datei in einer C-Datei mehrfach 
includierst z.B. durch geschachteltes Include von H-Dateien, die andere 
H-Dateien includieren.

Das löst aber keine Probleme, wenn du in zwei getrennten C-Dateien die 
gleiche H-Datei includierst. Wenn die H-Datei Variablen anlegt (i und 
fifo) werden die in beiden C-Dateien angelegt. Wenn sie dann beides male 
wie oben global sind, mosert der Linker, weil er jetzt i und fifo aus 
der einen und aus der anderen Objektdatei kennt. Zu Recht.

Abhilfe, wie oben mehrfach geschrieben, Variablen nicht in H-Dateien 
anlegen.

von Karl H. (kbuchegg)


Lesenswert?

Problemha-Bär wrote:
> ich dachte, um das zu umgehen gibt es die Befehle
>
> #ifndef
> #define
>
>
>
> ?

Die haben damit nicht das geringste zu tun.
Alle 'Befehle' die mit # beginnen werden vom
Präprozessor abgearbeitet und nicht vom Compiler.
Den Präprozessor kann man sich als Texteditor vorstellen,
der sich den Programmtext vornimmt bevor ihn der eigentliche
C-Compiler zu Gesicht bekommt. Das geile am Präprozessor
ist, dass die Kommandos an diesen Texteditor im Text
enthalten sind, den der Texteditor bearbeitet.

#define ...

ist einfach nur die Anweisung an diesen Texteditor (vulgo
Präprozessor) eine Textersetzung vorzunehmen.

#ifdef ...

ist das Kommando an den Präprozessor den danach folgenden
Text nur dann an den Compiler weiterzuleiten wenn eine
bestimmte Textersetzung vereinbart wurde.

Mehr steckt da nicht dahinter und beides hat nichts mit deinem
Problem zu tun.
Dein Problem dreht sich um den Unterschied zwischen
Definition und Dekleration.

Da darfst eine Variable mehrfach deklarieren solange alle
Deklarationen übereinstimmen. Du darfst aber eine Variable
nur einmal definieren.

Grob gesagt ist der Unterschied zwischen Deklaration und
Definition:
In einer Deklaration teilt man dem Compiler mit, dass etwas
existiert; welchen Namen es hat und welche Eigenschaften.
Ein Funktionsprotoyp ist eine Deklaration, aber auch eine
extern-Deklaration:

extern int bar;

Das sagt dem Compiler, dass es irgendwo im Gesamtsystem eine
Variable namens bar gibt, und dass sie vom Typ int ist. Der
Compiler möchte dies gerne wissen, damit er beim Übersetzen
von

void foo()
{
  bar = 5.0;
}

auch ermitteln kann, dass es tatsächlich eine Variable bar
gibt, und dass er bei der Zuweisung von 5.0 eine Konvertierung
von double auf int einbauen muss.

Bei einer Deklaration erzeugt der Compiler nichts im fertigen
EXE. Eine Deklaration ist lediglich die Information für den
Compiler, dass etwas existiert.

Im Kontrast dazu steht eine Definition. Eine Definition führt
dazu, dass im fertigen EXE etwas dafür erzeugt werden muss.
Sei das jetzt eine Funktion, die im EXE in Form von Code auftaucht
oder sei es eine Variablendefinition für die Speicherplatz
reserviert werden muss.

Das hier

int bar;

ist so eine Definition.

Für Definitionen gibt es aber eine Einschränkung: Es darf in
einem kompletten Programm immer nur eine Definition für etwas
geben (gcc hat hierfür eine Erweiterung eingebaut. Persönlich
halte ich nicht viel davon. Diese ODR [One Definition Rule]
ist in der Praxis kein Problem, so dass eine Erweiterung dafür
eigentlich nur dem einen Zweck dient: Der Faulheit und
Schlampigkeit von Programmierern nachzugeben).

Hast du also eine Header File und wird dieses Header File
von mehreren *.c Files (a.c, b.c) inkludiert, dann kann in diesem
Header File nur eine Deklaration von Variablen sein.

extern int bar;

Wäre das stattdessen eine Definition, so würde das dazu
führen, dass beim Übersetzen von a.c eine Definition für
bar gesehen wird und beim Übersetzen von b.c würde ebenfalls
eine Definition für bar gesehen (immer dran denken: a.c und
b.c werden unabhängig voneinander übersetzt!)

global.h
********

extern int bar;

a.c
***

#include "global.h"

void foo1()
{
  bar = 5;
}

b.c
***

#include "global.h"

void foo2()
{
  bar = 8;
}

Soweit so gut. Sowohl beim Übersetzen von a.c, als auch
beim Übersetzen von b.c wird dem Compiler mitgeteilt, dass
es irgendwo eine Variable namens bar gibt (es wird also
deklariert). Das ist gut so, nur irgendwo muss es diese
Variable auch tatsächlich geben; eine Definition und nur
eine Definition für bar muss irgendwo existieren. Du kannst
sie im Grunde in jedes beliebige *.c File machen. Machen wir
sie mal in a.c

a.c
****

#include "global.h"

int bar;   // hier existiert sie dann wirklich, die Variable bar

void foo()
{
  bar = 5;
}

von Karl H. (kbuchegg)


Lesenswert?

Problemha-Bär wrote:
> also es gibt keine Warnungen mehr wenn ich die beiden
>
> uint8_t   fifo[FIFO_MAX_ZEILE][FIFO_MAX_SPALTE];
> uint16_t   i;
>
> in die main.c als Globale Var. lege.
>
> Ich wollte sie aber ein bisschen trennen, da sie zum FIFO gehören.
> Geht also nit anders?


Da erhebt sich dann allerdings die Frage, was diese
Variablen überhaupt im Header File zu suchen haben.
Da sie offensichtlich nur zu einem FIFO Modul gehören
und die entsprechenden FIFO Funktionen ja in ein eigenes
fifo.c File gepackt werden sollten, liegt es doch Nahe, da
ebenfalls diese Variablen mit hineinzustecken.

Also: Raus aus dem Header File und zu den Funktionen
mit dazupacken.

Und da ausserhalb dieses FIFO Moduls niemand auch nur wissen
soll, dass es diese Variablen überhaupt gibt, ist es sinnvoll
auch den Zugriff von Ausserhalb mittels extern zu sperren und
die Variablen static zu machen.

von Problemha-Bär (Gast)


Lesenswert?

Alles klaro jetzt bei mir. Danke
Ich kann sie wohl nicht in eine fifo.c auslagern, da sie in der main.c 
gebraucht werden.
Sie kommen also in die main.c unter "globale variablen"

von Karl H. (kbuchegg)


Lesenswert?

Problemha-Bär wrote:
> Alles klaro jetzt bei mir. Danke
> Ich kann sie wohl nicht in eine fifo.c auslagern, da sie in der main.c
> gebraucht werden.

Das solltest du noch mal hinterfragen.
Warum werden sie in main gebraucht?
Kann man diese Funktionalität, die in main mit diesem
Variablen realisiert ist, nicht ebenfalls in eine
Funktion verpacken und diese Funktion zu den Fifo
Funktionen dazugeben?

> Sie kommen also in die main.c unter "globale variablen"

Dieser Beitrag ist gesperrt und kann nicht beantwortet werden.