Hallo,
ich habe in einem include file eine Variable definiert bzw. stand sie da
schon drin
uint8_t x;
Diese h-Datei wird in main.c includiert.
In der Hauptfunktion int main(void) {....} in main.c wird diese Variable
ohne weitere Deklaration benutzt. Ebenso in einem anderen c-file, zu dem
die h-Datei gehört. Der AVR Compiler meckert nicht, aber ich habe
manchmal Programmfehler, d.h. x scheint nicht den Wert zu haben, den es
haben soll.
1. Warum meckert der AVR-GCC Compiler nicht?
2. Sollte ich x in main.c vor der Hauptfunktion int main(void) {....},
also gloabal mit
uint8_t x;
definieren und dann in dem h-file mit
extern uint8_t x;
darauf verweisen/deklarieren und hat dann x immer den richtigen und
einen einzigen Wert in jedem c-file? Oder was wäre der richtige Weg?
3. Fehlt noch ein volatile?
Sorry, wurde so oder ähnlich bestimmt schon tausendmal gefragt, hab auch
gelesen, bin aber immer noch unsicher :-(
Rainer
Rainer K. schrieb: > die h-Datei gehört. Der AVR Compiler meckert nicht, aber ich habe > manchmal Programmfehler, d.h. x scheint nicht den Wert zu haben, den es > haben soll. > > 1. Warum meckert der AVR-GCC Compiler nicht? weil er eine Erweiterung hat, die dieses eigentlich nicht ganz koschere Vorgehen legitimiert. D.h. eigentlich ist das nicht das Bier des Compilers, denn der kann das gar nicht feststellen. Es ist das Bier des Linkers. Und der hat eine entsprechende Erweiterung. > 2. Sollte ich x in main.c vor der Hauptfunktion int main(void) {....}, > also gloabal mit > > uint8_t x; > > definieren und dann in dem h-file mit > > extern uint8_t x; > genau so macht man das. > 3. Fehlt noch ein volatile? Kann man so nicht beantworten. Ob du volatile brauchst oder nicht, hängt davon ab, wie die Variable benutzt wird. FAQ: Was hat es mit volatile auf sich
Der GNU Compiler legt uninitialisierte Variablen in das Common-Segement, der Linker Mehrfachdeklarationen im Common-Segment aber zusammen (das ist der spezifische Zweck dieses Segments). Das wird aus Gründen der Kompatibilität mit älteren Compilern so gemacht. Du kannst die Zusammenlegung verhindern (und die doppelten Definitionen beim Linken finden), indem du mit -fno-commons kompilierst. Dann werden alle Variablen in das BSS Segment gelegt, wo keine Duplikate erlaubt sind. Das übliche Verfahren ist: * Die Variable in einer Header-Datei mit extern deklarieren. * Die Variable in der dazugehörigen Source-Satei definieren. Genauso wie man es mit Funktionen machen würde.
Karl Heinz Buchegger schrieb: > weil er eine Erweiterung hat, die dieses eigentlich nicht ganz koschere > Vorgehen legitimiert. Naja, das Vorgehen ist vom Standard als eine von zwei möglichen Varianten abgedeckt, insofern stimm "nicht ganz koscher" und "Erweiterung" gar nicht.
Dann muss sich das in einem der letzten beiden Standards geändert haben. Meine letzt Info bezieht sich auf die One Definition Rule.
Karl Heinz Buchegger schrieb: > Dann muss sich das in einem der letzten beiden Standards geändert haben. > Meine letzt Info bezieht sich auf die One Definition Rule. Die gibt es nicht. ;-) Schau' dir mal das Rationale zu Kapitel 6.2.2 an.
> 6.2.2 spricht von der Linkage Hmm. Ich sehe was du meinst. > Each declaration of an identifier with no linkage denotes a unique > entity. Auf der anderen Seite sagt 6.7 / 3 > If an identifier has no linkage, there shall be no more than one > declaration of the identifier (in a declarator or type specifier) > with the same scope and in the same name space, except for tags > as specified in 6.7.2.3. (6.7.2.3 spricht über enums und so'n Zeugs)
Karl Heinz Buchegger schrieb: > Auf der anderen Seite sagt 6.7 / 3 >> If an identifier has no linkage, there shall be no more than one >> declaration of the identifier (in a declarator or type specifier) >> with the same scope and in the same name space, except for tags >> as specified in 6.7.2.3. Ja, "in the same scope". Wir reden aber über verschiedene translation units. Dat's der Punkt hier.
> For each different entity that an identifier designates, the > identifier is visible (i.e., can be used) only within a region > of program text called its scope. Different entities designated > by the same identifier either have different scopes, or are in > different name spaces. Hmm. In welchem Scope sind globale Variablen?
Moment mal. Da muss ich mich erst mal durchkämpfen. Das ist mir so im Detail nicht mehr geläufig.
Hab meinen Fehler. Scope regelt ja nur die Sichtbarkeit und damit die Referenzierbarkeit. Trotzdem puzzelt mich dieser Teil 6.2.2 / 2 (Mein Bauch sagt: Da ist was faul) Wobei ich sagen muss, das mich hier der C-Standard sowieso eher verwirrt mit seiner generellen Verwendung des Terms "Declaration".
Karl Heinz Buchegger schrieb: > In welchem Scope sind globale Variablen? File scope. Karl Heinz Buchegger schrieb: > Trotzdem puzzelt mich dieser Teil 6.2.2 / 2 > (Mein Bauch sagt: Da ist was faul) Naja, man wollte eben vorsätzlich nicht mit der Unix-Tradition und dem "common"-Modell brechen. Schließlich soll so ein Standard in der Regel erstmal Dinge so festschreiben, wie sie bislang auch gehandhabt wurden. > Wobei ich sagen muss, das mich hier der C-Standard sowieso eher verwirrt > mit seiner generellen Verwendung des Terms "Declaration". Constraint #5 in Abschnitt 6.7 regelt, wann eine Deklaration zu einer Definition wird.
Jörg. Hil fmal meinem Verständnis auf die Sprünge > 1 An identifier declared in different scopes or in the same scope > more than once can be made to refer to the same object or function > by a process called linkage.21) There are three kinds of linkage: > external, internal, and none. So weit so gut. Auch wenn mir nicht klar ist, wozu 'none' gut sein soll. > 2 In the set of translation units and libraries that constitutes > an entire program, each declaration of a particular identifier > with external linkage denotes the same object or function. Soweit so gut. Zusammen mit der Erklärung weiter unten ist damit klar, alle "extern" beziehen sich auf das gleiche Objekt. > Within one translation unit, each declaration of an identifier > with internal linkage denotes the same object or function. Auch ok. In einer Translation Unit kann es mehrere 'static' Objekte geben, die alle gleich heißen und die in diesem Fall alle nur ein Objekt sind. > Each declaration of an identifier with no linkage denotes a > unique entity. Aber worauf bezieht sich jetzt das?
1 | int i; |
2 | |
3 | void foo() |
4 | {
|
5 | }
|
1 | int i; |
2 | |
3 | void bar() |
4 | {
|
5 | }
|
Angenommen das wäre der Fall. Wo ist da jetzt der Unterschied zu 'static' auf File-Scope (salopp ausgedrückt)? Was entgeht mir da?
Karl Heinz Buchegger schrieb: > Was entgeht mir da? Mein Gedächtnis kramt da rum und bringt was hoch. Hat es nicht schon vor einiger Zeit eine Änderung gegeben, nach der Variablen auf File-Scope als Default nicht mehr 'externe Sichtbarkeit' sondern 'File static Sichtbarkeit' bekamen. (*) (Meine Beschreibung, ich hoffe du verstehst was ich meine). Ist das die Wirkung von "none" - als einer Art Default-static zu fungieren? (*) Etwas was in C++ noch aussteht.
Karl Heinz Buchegger schrieb: > Aber worauf bezieht sich jetzt das? > Angenommen das wäre der Fall. Wo ist da jetzt der Unterschied zu > 'static' auf File-Scope (salopp ausgedrückt)? Dass 'static' sie nur für die aktuelle Übersetzungseinheit benennt. Benutzt eine andere Übersetzungseinheit ebenfalls ein
1 | static int i; |
dann bezeichnet dieses `i' ein anderes Objekt als jenes `i'. Ohne `static' bezeichnen sie das gleiche `i'. Ob es dann zu einem Linkerfehler kommt (Doppeldefinition, weil bei einer von beiden Deklarationen kein `extern' steht) oder nicht, hängt vom benutzten Modell für die external linkage ab.
Karl Heinz Buchegger schrieb: > Hat es nicht schon vor einiger Zeit eine Änderung gegeben, nach der > Variablen auf File-Scope als Default nicht mehr 'externe Sichtbarkeit' > sondern 'File static Sichtbarkeit' bekamen. Nein, leider nicht.
> Ob es dann zu einem Linkerfehler kommt (weil bei einer von > beiden Deklarationen kein `extern' steht) oder nicht, hängt > vom benutzten Modell für die external linkage ab. Also unspecified. Hmm.
Jörg Wunsch schrieb: > Constraint #5 in Abschnitt 6.7 regelt, wann eine Deklaration zu > einer Definition wird. Schon. Aber ich finde in der Verwendung im restlichen Standard kaum Unterscheidungen zwischen Declarations und Definitions. Es muss doch auch Passi (Plural von Passus) geben, in denen mehr oder weniger steht: hier geht nur eine Declaration, die keine Definition ist.
Super, dass ihr sofort so tief einsteigt :-) Ist mir aber schon zu hoch... Ist es denn denkbar, dass die Variable in main.c undefinierte Werte haben kann, wenn man es so macht wie ich es beschrieben habe (die Variable wurde nur in der main Funktion verändert, bzw. abgefragt)? Normalerweise denke ich immer, compiliert/linkt ohne Fehler, also ist alles (bis auf meine eigenen Programmablauf- und Denkfehler :-)) richtig. Leider hat das Programm auch unterschiedlich oft richtig funktioniert und dann plötzlich nicht mehr und dann habe ich angefangen zu suchen... Rainer
Rainer K. schrieb: > Ist mir aber schon zu hoch... Da gehts eigentlich mehr um 'Gesetztes-"Auslegung"' :-) > Normalerweise denke ich immer, compiliert/linkt ohne Fehler, also ist > alles ui. Davon musst du weg. dem ist nicht so. Einfaches Beispiel
1 | extern uint8_t * pPtr; |
2 | ...
|
1 | uint8_t pPtr[10]; |
2 | ...
|
Mööp. Gerade bei Translation-Unit-übergreifenden Dingen bist du mehr auf dich alleine gestellt, als dir lieb ist. Behalte immer im Hinterkopf: C hat 'traditionell' nur sehr rudimentäre Fähigkeiten, wenn es um den Projektgedanken (d.h. ein Programm besteht aus mehreren Files/Libraries) geht. Da gibts genug Dinge, vor denen dich weder Compiler noch Linker schützen.
Karl Heinz Buchegger schrieb: >> Ob es dann zu einem Linkerfehler kommt (weil bei einer von >> beiden Deklarationen kein `extern' steht) oder nicht, hängt >> vom benutzten Modell für die external linkage ab. > > Also unspecified. Implementation-defined, würde ich aus dem Bauch raus sagen. Rainer K. schrieb: > Ist es denn denkbar, dass die Variable in main.c undefinierte Werte > haben kann, wenn man es so macht wie ich es beschrieben habe Nein. Ansonsten hatte Karl-Heinz alles bereits erschöpfend beantwortet: Beitrag "Re: Verständnisfrage C-Programmierung AVR-GCC"
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.