Forum: Mikrocontroller und Digitale Elektronik doppelte definition


von roberto (Gast)


Lesenswert?

Ich habe ein Problem, das womöglich etwas Einfaches ist.

In einem h-file rechner.h habe ich sowie Funktionsprototypen als auch 
eine Variablendeklaration.

Das Konstrukt sieht so wie angegeben aus.
Wenn ich das File im main.c einbinde mittels include kommt die Meldung 
symbol multiply defined.
Weshalb denn?
Das h-File mit dem Inhalt wird genau an der Stelle eingefügt, wo es im 
main.c steht.
Ich verstehe das Problem irgendwie nicht.

#include "stm32l4xx_hal.h"

/* Define to prevent recursive inclusion 
-------------------------------------*/
#ifndef RECHNER_H
#define RECHNER_H



uint8_t a;

void Rechner_Init (void);
#endif /* RECHNER_H */

von Jim M. (turboj)


Lesenswert?

Lies ein Anfänger Buch über die Programmiersprache "C". Die ist 40 Jahre 
alt und alles andere als selbsterklärend.

von MikeH (Gast)


Lesenswert?

Du hast eine Definition und keine Deklaration im Headerfile.

Schreib ins Headerfile: extern uint8_t a;
und in eine C-Datei: uint8_t a;

von W.S. (Gast)


Lesenswert?

roberto schrieb:
> Wenn ich das File im main.c einbinde mittels include kommt die Meldung
> symbol multiply defined.
> Weshalb denn?

Weil es dir am Grundveständnis fehlt.

Also:
Eigentlich schreibt man erstmal alles, was man in C programmiert, in 
Quellcode-Dateien, die üblicherweise auf .c enden.

Wenn du nun so eine Datei hast, ich nenne die mal ottokar.c, und willst 
aus einer anderen Datei (z.B. aus karlheinz.c) auf eine Funktion (sagen 
wir mal void emil(void)) oder Variable (sagen wir mal int kunigunde ) 
zugreifen, die in ottokar.c steht, dann hast du ein Problem, denn weder 
emil noch kunigunde sind von karlheinz aus sichtbar.

Nun hat C kein Modulsystem wie z.B. Pascal, wo man Dinge, die man aus 
einem Unit heraus der Öffentlichkeit offenbaren will, in die 
'interface'-sektion schreiben kann.

Ersatzesweise gibt es aber als allgemeine Konvention die sogenannten 
Headerfiles, die zumeist auf .h enden. Dort schreibt man all das hinein, 
was man aus der zugehörigen .c der Allgemeinheit offenbaren will. Diese 
.h Datei bindet man dann dort ein, wo man die Informationen benötigt.

Damit das der Compiler auch wirklich als Verweis auf eine andere Datei 
kapiert, schreibt man das Wort 'extern' davor. Bei Funktionen kann man 
das extern auch weglassen, dann wäre es lediglich eine 
Vorwärts-Deklaration, über die sich der C-Compiler jedoch nicht 
beschwert. Ich selber neige dazu, für alles Externe auch immer extern 
davorzuschreiben, ist schlichtweg einheitlicher.

als Beispiel:
in ottokar.h steht
1
#ifndef diesistottokardertoeffel
2
#define diesistottokardertoeffel
3
extern int  kunigunde;
4
extern void emil(void); // hier kannst du das extern weglassen
5
#endif

in ottokar.c steht
1
#include "ottokar.h"
2
int  kunigunde;
3
void emil(void)
4
{ hier irgendwas
5
}

Nun kannst du in karlheinz.c so schreiben:
1
#include "ottokar.h"
2
kunigunde = 1;
3
emil();

Die jeweils eigene .h bindet man zweckmäßigerweise in die .c Datei mit 
ein, damit bei etwaigen Konsistenzfehlern zwischen dem Verweis in .h und 
der eigentlichen Deklaration in .c der Compiler meckern kann.

Wie gesagt, diese .h Headerfiles kann man benutzen, man muß es jedoch 
nicht. Aber es hat sich als Üblichkeit etabliert.

Man kann sie auch benennen wie man will, aber die Endung .h ist auch 
eine Üblichkeit.

Man kann auch die Zeilen mit dem #ifndef xxx.. #define xxx... #endif 
weglassen, muß dann aber selber aufpassen.

Und nochwas:
in eine Headerdatei soll bittesehr nur das hineinkommen, wa man von 
anderen Programmteilen her auch wirklich benötigt - und nicht mehr. Das 
wären die zu exportierenden Variablen und Funktionen und wenn nötig auch 
Typdefinitionen (die brauchen kein 'extern', da sie ja nur einen Typ 
erklären und selber keine Variable sind).
Also keine Romane und keine Interna in .h schreiben.

W.S.

von roberto (Gast)


Lesenswert?

W.S. schrieb:
> roberto schrieb:


> Man kann sie auch benennen wie man will, aber die Endung .h ist auch
> eine Üblichkeit.
>
> Man kann auch die Zeilen mit dem #ifndef xxx.. #define xxx... #endif
> weglassen, muß dann aber selber aufpassen.
>
> Und nochwas:
> in eine Headerdatei soll bittesehr nur das hineinkommen, wa man von
> anderen Programmteilen her auch wirklich benötigt - und nicht mehr. Das
> wären die zu exportierenden Variablen und Funktionen und wenn nötig auch
> Typdefinitionen (die brauchen kein 'extern', da sie ja nur einen Typ
> erklären und selber keine Variable sind).
> Also keine Romane und keine Interna in .h schreiben.
>
> W.S.

Vielen Dank W.S für die ausfühliche Erklärung.
Das klappt so.
Strukturen benötigen, soviel ich weiss auch keine extern's.

von Adam P. (adamap)


Lesenswert?

roberto schrieb:
> Strukturen benötigen, soviel ich weiss auch keine extern's.

Wenn du sowas meinst:
1
struct foo
2
{
3
  uint8_t a;
4
  uint8_t b;
5
};

dann benötigst du kein "extern" da du dem Compiler nur mitteilst, wie 
diese Struktur definiert ist (wie sie aufgebaut ist).

Willst du diese Struktur verwenden, musst du eine Variable vom Typ der 
Struktur anlegen, dabei wird Speicherplatz reserviert und du kannst die 
Variable nutzen:
1
struct foo meine_struktur;

dann benötigst du das extern, wenn du es in die Header schreiben willst.

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.