Forum: Mikrocontroller und Digitale Elektronik System Workbench for STM32, globale Variable


von Uwe M. (drosiusingolf)


Lesenswert?

Schönen guten Tag Freunde der Elektronik!

Bei meinen bisherigen IDEs für Arm Cortex (Atmel Studio und IAR 
Workbench) hatte ich im main.c File immer problemlos die anderen Files 
wie folgt eingebunden:

#include "stdint.h"   //nur benötigt wegen uintx_t Variablen
#include "own_def.h"
#include "global.h"
#include "interrupts.c"
#include "hw.c"

Allerdings stoße ich bei System Workbench for STM32 von AC6 (=Eclipse) 
auf heftige Gegenwehr. So muß ich die Headerdateien in jedem .c File 
vorstellen. Scheinbar werden die #includes nicht im main.c aufgelöst, 
sprich deren Inhalte nicht aneinander gereiht, so daß die Funktionen der 
Sourcefiles nicht die Definitionen der h.Files sehen. Hat das was mit 
einem evtl. Einpassverhalten des internen Compilers zu tun?

Mit der zusätzlichen Einbindung der h-Files kann ich noch leben. 
Allerdings kracht es dann bei den globalen Variablen. Diese in global.h 
(enthält nur eine momentan) geht gar nicht. So meckert hw.c über die 
angeblich nicht deklarierte Variable. Stelle ich diese in hw.c als 
extern uint32_t errors vor, ergibt dies über 200 Fehler("first defined 
here"), obwohl diese Variable nur an etwa 2 Stellen auftaucht. Ohne das 
extern Attribut passiert das Gleiche. Was mache ich falsch, kann ich den 
Compiler ggf. auf 2 Pass Verhalten umstellen?

Frustrierte Grüße,

Uwe

: Bearbeitet durch User
von pegel (Gast)


Lesenswert?

Ich weiss nicht, ob ich das richtig verstanden habe, aber ändert sich 
das Verhalten wenn du ein "Index->Rebuild" ausführst?

von Uwe M. (drosiusingolf)


Lesenswert?

pegel schrieb:
> Ich weiss nicht, ob ich das richtig verstanden habe, aber ändert sich
> das Verhalten wenn du ein "Index->Rebuild" ausführst?

Hallo Pegel!

Es ändert sich leider nichts.

von pegel (Gast)


Lesenswert?

Dann wäre es vielleicht sinnvoll ein absolutes Minimal Beispiel zu 
erstellen.
Das kannst du hier anhängen, dann könnte ich und auch andere das Problem 
nachvollziehen.

von Uwe M. (drosiusingolf)


Lesenswert?

Gute Idee, mache ich!

von Harry L. (mysth)


Lesenswert?

Uwe M. schrieb:
> #include "interrupts.c"
> #include "hw.c"

Das lässt grundsätzliche Defizite bei den C-Grundlagen vermuten.
Da wundert es wenig, wenn es Fehlermeldungen nur so hagelt....

Sowas tut man nicht!

Der Unterscjied zwischen
1
#include "foo.h"
und
1
#include <foo.h>
scheint dir auch nicht ganz klar zu sein.

: Bearbeitet durch User
von Jim M. (turboj)


Lesenswert?

Uwe M. schrieb:
> #include "hw.c"

Wieso zum Teufel #includest Du eine *.c Datei? Wenn Du sie #includest, 
musst Du sie .h nennen oder die IDE kommt furchtbar durcheinander.

Denn die IDE geht davon aus das alle *.c Dateinen einzeln compiliert 
und dann später zusammem verlinkt werden.

Der Indexer jagt die *.c Dateien einzeln duch den Compiler.

von Stefan F. (Gast)


Lesenswert?

Man includiert keine *.c Dateien und man deklariert keine Variablen in 
*.h Dateien.

Informiere Dich mal über den Sinn von Header Dateien.

Wenn du eine globale Variable in allen *.c Dateien verfügbar machen 
willst, musst du das Schlüsselwort extern benutzen. Aber das wäre 
ziemlich schlechter Stil.

Sauber wäre, die Variable in einer *.c Datei zu haben, zusammen mit 
getter- und setter- Funktionen. Diese wiederum werden über eine 
gleichnamige *.h Datei den anderen Quelltexten bekannt gemacht.

von Harry L. (mysth)


Lesenswert?

Stefanus F. schrieb:
> Sauber wäre, die Variable in einer *.c Datei zu haben, zusammen mit
> getter- und setter- Funktionen. Diese wiederum werden über eine
> gleichnamige *.h Datei den anderen Quelltexten bekannt gemacht.

Da verwechselst du wohl C und C++.
In C ist es durchaus üblich (und wird auch so gelehrt), globale 
variablen in einer Header-Datei als extern zu deklarieren.
Daran ist nichts "unsauber".

von Uwe M. (drosiusingolf)


Lesenswert?

Harry L. schrieb:
> Der Unterscjied zwischen#include "foo.h"
> und#include <foo.h>
> scheint dir auch nicht ganz klar zu sein.

Da ich ALLE Dateien in einem Arbeitsverzeichnis habe, sind meine 
#includes "xyz" korrekt. Was gibt es da zu bemängeln? Allerdings nehme 
ich den Vorwurf mit dem Inkludieren der c-files sehr ernst, danke!

Und in der Tat kannte ich die Indexer Funkion bisher überhaupt nicht, da 
ich nicht sonderlich gut die Internas von Compilertechniken kenne. Ich 
mache mich da mal fit, klingt interessant, danke!

: Bearbeitet durch User
von Johannes S. (Gast)


Lesenswert?

Der Compiler wird das Main.c Chaos mit den .c includes fehlerfrei 
übersetzen, solange keine Symbole mehrfach vorkommen ist das erstmal von 
der Syntax ok. Include fügt die angegebene Datei nur an diese Stelle 
ein.
Das CDT von Eclipse das das Projekt scannt und makefiles erzeugt findet 
aber auch die anderen C Quellen und übersetzt die auch. Wenn die 
fehlerfrei waren wird der Linker jetzt aber meckern weil Symbole doppelt 
vorhanden sind, einmal im Main.o und dann in denn jeweiligen anderen 
Modulen.

von Harry L. (mysth)


Lesenswert?

Uwe M. schrieb:
> Da ich ALLE Dateien in einem Arbeitsverzeichnis habe, sind meine
> #includes "xyz" korrekt. Was gibt es da zu bemängeln?

stdint.h ist ein system-weit verfügbarer Header, und muß daher mit
1
#include <stdint.h>   //nur benötigt wegen uintx_t Variablen
referenziert werden weil der Pfad zwar in der Liste der Include-Pfade 
des Compiler steht (stehen sollte) aber ansonsten je nach 
Entwicklungsumgebung- variabel ist.

Offensichtlich hast du das ja noch nicht ganz vollständig verstanden.

von Uwe M. (drosiusingolf)


Lesenswert?

Bevor man mich verbal (weiter) zerreißt, hier noch die Intention meines 
klar experimentellen Codes. Diesen habe ich übrigens mittlerweile nach 
den klassischen Regeln kompiliert bekommen mit einiger Schreibarbeit.

Und da sind wir nun bei meiner ursprünglichen Intention: Wenn man alles 
in einer Datei programmieren würde, könnte man sich einiges an 
Schreibarbeit ersparen: Prototypen von Funktionen, Verweis auf externe 
Variablen. Natürlich wäre so eine einzige Datei extrem lang, 
unübersichtlich und daher chaotisch, weiß ich, habe vor zuletzt 16 
Jahren selber codiert. Und da dachte ich mir rein experimentell, ich 
lagere aus dieser langen Datei (im Anfangsstadium) strukturiert aus, 
Treiberteil in hw.c, Interrupthandler in interrupts.c, aber diese Teile 
müssen zum Zeitpunkt der Compilierung wieder zu einem Teil (der 
ursprünglichen großen Datei) zusammenfinden mit Hilfe von includes, für 
den Programmierer natürlich unsichtbar. Aber leider scheint es paar 
Nebeneffekte zu geben, die mir wegen fehlendem tiefen 
Compilerkenntnissen verborgen blieben. Schade, aber im Ansatz eine nette 
Idee.
Gruß und vielen Dank,

Uwe

von Kaj (Gast)


Lesenswert?

Harry L. schrieb:
> In C ist es durchaus üblich (und wird auch so gelehrt), globale
> variablen in einer Header-Datei als extern zu deklarieren.
> Daran ist nichts "unsauber".
Nur weil es "ueblich" ist, ist es noch lange nicht gut. Und es ist 
unsauber. Denn wenn du die Variable mal umbenennen musst, dann musst du 
viele Dateien anfassen. Mit einer sauberen Schnittstelle durch 
Funktionen muss nur eine einzige Datei angefasst werden. Auch das 
Debuggen ist deutlich aufwaendiger. Gestattet man den Zugriff nur ueber 
Funktionen, habe ich max. 2 Stellen an denen die Variable veraendert 
wird und an denen ich einen Breakpoint setzen muss: in der set- und in 
der get-Funktion.

Machst du eine globale Variable ueber extern bekannt, hast du halt kein 
sauberes API zwischen den Code-Modulen... aber wer braucht das schon. Da 
trennen sich halt die echten Maenner von den Muesliessern...

von Johannes S. (Gast)


Lesenswert?

Uwe M. schrieb:
> Und da sind wir nun bei meiner ursprünglichen Intention: Wenn man alles
> in einer Datei programmieren würde,

Dazu fehlt mir nur ein: 'kann man so machen, dann ist es halt Kacke'.
Das es nicht geht liegt nicht am Compiler sondern wie beschrieben am 
Automatismus des CDT Builders. Der sucht alle Projektverszeichnisse nach 
.c/.cpp Dateien ab und fügt die in makefiles ein. Damit werden deine .c 
doppelt compiliert, einmal als include im main und einmal einzeln. Und 
dabei fehlen dir die Includes in interrupt.c weil du die nur vorher im 
main angegeben hast. Aber was in main.c steht das interessiert 
interrupt.c nicht die Bohne.
Es wird funktionieren wenn du alle .c files ausser main.c vom Build 
ausschliesst. Das geht in Eclipse: Rechtsklick auf die .c Datei, 
Resource Configurations / Exclude from Build... und da alle auswählen.
Aber wie gesagt, das ist gegen Modularisierung und verhindert 
inkrementelle builds (nur das übersetzen was sich geändert hat). Ich 
würde es nicht so machen. Das ist genauso blöd wie der Arduino .ino 
Mist, nur weil man den Leuten nicht zumuten möchte das 
Implementierung/Interface Konzept verstehen zu sollen.

von Jens (Gast)


Lesenswert?

Kaj schrieb:
> Denn wenn du die Variable mal umbenennen musst, dann musst du
> viele Dateien anfassen.

Wenn das der einzige Grund ist: heute gibt es IDEs die refactorieren. 
Ein Klick und die Variable ist überall unbenannt. Und jeder Profi 
benutzt eine IDE und kein Editor-Makefile gewurstel.

von Uwe M. (drosiusingolf)


Lesenswert?

Kaj schrieb:
> Mit einer sauberen Schnittstelle durch
> Funktionen muss nur eine einzige Datei angefasst werden

Klingt sicherlich gut, optisches Software Engineering vom Feinsten, aber 
über den dramatischen Geschwindigkeitsverlust beim Lesen und Beschreiben 
dieser Variablen, geschätzt etwa  etwa Faktor 5, schweigst du dich 
natürlich aus.... Fazit: Es gibt keine tolle Lösung für globale 
Variablen!

von STK500-Besitzer (Gast)


Lesenswert?

Kaj schrieb:
> enn wenn du die Variable mal umbenennen musst, dann musst du
> viele Dateien anfassen

Oder vorher mal einen sinnvollen bzw. den gewünschten Namen verwenden.
Da die meisten mit einer IDE programmieren dürften, sollte es damit auch 
per Suchen/Ersetzen problemlos möglich sein.

Uwe M. schrieb:
> Diesen habe ich übrigens mittlerweile nach
> den klassischen Regeln kompiliert bekommen mit einiger Schreibarbeit.

Schon mal was von der Zwischenablage gehört?

Die Geschichte mit dem extern in der Header-Datei hat auch was von 
Datenkapselung: Variablen, die nur in der C-Datei auftauchen, können 
auch nur dort von diesem "Modul" verwendet werden.
Gibt man sie mir extern (sieht hübsch aus, ist aber mWn nicht mehr 
nötig) in der Header-Datei an, können auch andere Module schreibend 
darauf zugreifen.
Das umgeht Kay durch die Verwendung von Funktionen (die in der 
Header-Datei dann aufgeführt werden müssen, damit andere Module darauf 
zugreifen können).

Kaj schrieb:
> Gestattet man den Zugriff nur ueber
> Funktionen, habe ich max. 2 Stellen an denen die Variable veraendert
> wird und an denen ich einen Breakpoint setzen muss:

> in der set- und in  der get-Funktion.
Schweifen wir jetzt in die objektorientierte Programmierung ab?

von W.S. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Wenn du eine globale Variable in allen *.c Dateien verfügbar machen
> willst, musst du das Schlüsselwort extern benutzen. Aber das wäre
> ziemlich schlechter Stil.

Ähem..
ich mache das mal konkret:
in blabla.c schreibt man beispielsweise
int MeineVariable;

und im zugehörigen blabla.h schreibt man
extern int MeineVariable;

und wie schon geschrieben wurde, inkludiert man NICHT die .c Datei, 
sondern nur die zugehörige .h Datei in anderen Programm-Moduln.

Man kann das seit geraumer Zeit so machen, daß man alles was man an 
Variablen und Funktionen in die .h schreibt, mit extern versieht. Auch 
Funktionen. Das übersieht zwar der Compiler, aber es ergibt sich damit 
eine vereinheitlichte Darstellung in der Headerdatei, was zumindest ich 
als positiv empfinde, weil damit eine Extrawurst für Funktionen 
beseitigt ist.

W.S.

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.