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
Ich weiss nicht, ob ich das richtig verstanden habe, aber ändert sich das Verhalten wenn du ein "Index->Rebuild" ausführst?
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.
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.
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
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.
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.
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".
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
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.
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.
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
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...
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.
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.
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!
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?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.