Hallo an alle! Ich habe anscheinend ein grundlegendes Verständnisproblem mit dem Gültikeitsbereich mit Pointern, da mich das gestern Stunden an Zeit kostete, einen Fehler in einem kleinen Programm zu finden und auch das nur durch Zufall. Also: Ein Pointer hat so wie ich das verstanden habe den selbe Gültikeitsbereich wie jede andere variable, unabhängig vom Datentyp. Wenn ich also zu Beginn des Programmes (vor allen Funktionen und Klammern schreibe: volatile uint8_t *port; Dann ist der Pointer "port" ja global deklariert, richtig? SO und nun folgendes Beispiel: In meinem weiteren Programm gibt es die Funktionen: int debounce_pin(volatile uint8_t *port, uint8_t pin) ISR(TIMER0_OVF_vect) und int main(void) Nun hatte ich den Fehler, dass ich der meinung war, wenn der Pointer "port" ganzoben global deklariert ist, dass der in allen Funktionen des Programmes bekannt sei....war er aber nicht! Nun frag ich euch, warum nicht! Ich kam dahinter, dass mir die Zuweisung des Pointers fehlte, was nun so aus sieht und auch funktioniert: port = &PINC //Dem pointer die Adresse von PINC übergeben Schön und gut, ABER: Ich war immer der Meinung, dass variablen immer nur innerhalb der Klammern, in denen Sie stehen, gültig sind.(außer globale und "port" ist doch global?!) Wenn ich nun diese Pointerzuweisung in in die Funktion, in der "port" dereferenziert wird schreibe,funktioniert das ganze Programm, wenn ich es allerdings ins main Programm schreibe, funktioniert es AUCH!! Nun dachte ich mir, dass liegt daran, das "port" ja gobal definiert ist. Sschreibe ich aber die Zuweisung in eine andere Funktion, geht gar nichts mehr. Die Frage, die sich mir also stellt: Ist es richtig, dass der Gültigkeitsbereich nicht von der Deklaration der variable anhängt (wo die steht), sondern wo im Programm die Zuweisung passiert?? Bin für jede Hilfe dankbar !! Grüße Helmut
Du benutzt zwei Pointer mit dem gleichen Namen, einer davon wird beim Eintritt in 'debounce_pin' auf dem Stack angelegt, eine liegt im Bereich der statischen, globalen Variablen. Wenn 'debounce_pin' betreten wird, gilt innerhalb dieser Funktion nur die Referenz auf den Stack. Wird sie verlassen, wird natürlich auch dieser Pointer ungültig und damit "Zerstört".
P.S.: Die Zuweisung funktioniert auch NICHT, wenn ich die direkt nach der Deklaration der pointers ganz zu Beginn mache: volatile uint8_t *port; port = &PINC; Warum nicht?
Na gut aber was ich mich nun frage ist: Wenn ich der Funktion: int debounce_pin(volatile uint8_t *port, uint8_t pin) so etwas übergebe: debounce(&PINC,PINC0); Funktioniert das, egal, wie ich den ersten parameter bei der Definition der FUnktion debounce heißt, das funktioniet ja auch,wenn die Funktion so aussieht: int debounce_pin(volatile uint8_t *test, uint8_t pin) Das versteh ich nicht so ganz. In diesem Falle wird beim Betreten der Funktion debounce ein pointer "erstellt?", der den Namen "test" hat. In diesem Falle ist ja egal, wie ich diesen pointer nenne, richtig? Der poiter "test" hat also nur gültigkeit innerhalb eines Aufrufes von debounce?
> Warum nicht?
Weil du Patricks Antwort noch nicht verstanden hast.
Benenne deinen Funktionsparameter um von "port" auf "p" oder
sowas, dann hast du sowohl "port" (global) als auch den
Parameter (lokal) zur Verfügung innerhalb der Funktion.
> Der poiter "test" hat also nur gültigkeit innerhalb eines Aufrufes > von debounce? Ja, genauso wie "pin". Alle Funktionsparameter erzeugen lokale Variablen innerhalb der Funktion, ob sie nun Pointer sind oder nicht, spielt dabei keine Rolle.
"Benenne deinen Funktionsparameter um von "port" auf "p" oder sowas,dann hast du sowohl "port" (global) als auch den Parameter (lokal) zur Verfügung innerhalb der Funktion." Nun, heißt das, dass der globale Pointer und der lokale nicht gleich heißen dürfen, da sonst beim Eintritt in die Funktion "debounce" plötzlich zwei Pointer mit dem selben Namen existieren?
Sie dürfen schon gleich heißen. Allerdings kannst du dann aus der Funktion heraus auf den globalen nicht zugreifen. Es wird immer der lokale verwendet.
Dürfen darfst du schon. Innerhalb der Funktion existiert aber nur der lokale Name; der globale wird damit überschattet und ist dort nicht zugreifbar. Wie sollte auch der Compiler ahnen, welchen der beiden Zeiger mit dem Namen "port" du gerade meinst? Im Grunde genommen kannst du sogar doppelte Überschattung haben:
1 | void *port; |
2 | |
3 | void foo(void *port) |
4 | {
|
5 | void *port; |
6 | ...
|
7 | }
|
In diesem Falle würde die lokale Variable namens port den Parameter namens port überschatten (das generiert eine Compilerwarnung), der Parameter wiederum überschattet die globale Variable namens port (das generiert keine Compilerwarnung). Aber wie geschrieben: mit Zeigern hat das nichts zu tun, das sind ganz allgemeine Namensregeln für Variable.
WO ich nicht durchblicke ist: Wenn ich ganz zu Beginn schreibe(wie schon oben erwähnt) : volatile uint8_t *port; port = &PINC; Dann habe ich einen globalen Pointer mit dem Namen "port", der die Adresse von PINC enthält. Mal abgesehen von der zusätzlichen lokalen Pointer-Variable in der debounce Funktion(diese wurde ja noch gar nicht aufgerufen), sollte nun in der ISR zumindest der globale Pointer richtig initialisiert sein. Ich bekomme aber einen Fehler, wenn ich in der ISR , den pointer dereferenzieren möchte mit: neuevariable = *port & (1 << pin); SO als ob er nicht bekannt wäre..... Wie gesagt, dass alles hat ja noch gar nichts zu tun mit dem lokalen Pointer in "debounce"?
Wenn du dir jetzt noch die Fehlermeldung nicht aus der Nase ziehen ließest, könnte dir geholfen werden... Am besten gleich ein komplettes, compilierbares Stück Code als Attachment.
Ok, hier das gesamte Programm, kompilierbar mit avr-gcc (GCC) 3.4.5 Die Frage habe ich als Kommentar neben die betroffene Zeile geschrieben ;-)
Umm, oh, bitte keine Headerfiles aus der Bibliothek in dein Projekt mit hineinlegen. Wenn die Bibliothek mal aktualisert wird, benutzt du dann (u. U.) noch die alten Dateien. Damit man das Ganze auch ohne all die lokalen Kopien noch compilieren kann, musst du aus #include "interrupt.h" ein #include <avr/interrupt.h> machen.
1 | port = &PINC; //WARUM DARF DIESE ZEILE NICHT GANZ OBEN STEHEN UNTER |
2 | //DER DEKLARATION DES GLOBALEN POINTERS?
|
Weil sie ausführbarer Code ist, der darf in C nur innerhalb von Funktionen auftauchen. Außerhalb von Funktionen dürfen nur Deklarationen und Definitionen stehen, kein Code selbst. Was aber geht ist eine Initialisierung auf globaler Ebene:
1 | volatile uint8_t *port = &PINC; |
Das ist kein ausführbarer Code, sondern es beschreibt eine Vorbelegung der Variablen "port" mit einem Wert. Diese Vorbelegung generiert der Compiler bereits zur Compilezeit, wobei er im Falle des AVR dann zur Laufzeit während des Starts ein wenig Hilfe vom startup code braucht, damit dieser die RAM-Zellen aus dem ROM initialiert.
AAhhhh... "Weil sie ausführbarer Code ist, der darf in C nur innerhalb von Funktionen auftauchen. Außerhalb von Funktionen dürfen nur Deklarationen und Definitionen stehen, kein Code selbst." Das sollte man halt wissen :-P Danke für deine Mühe, Jörg!! Ab jetzt werd ich wohl öfters diese "Initialisierung auf globaler Ebene" vornehmen, erspart eine Menge Ärger :-)
Achja, eines noch! Wie das mit der globalen und der lokalen Deklaramtion und der Namensgebung von Variablen funktioniert, hab ich nun glaub ich verstanden. Was mir noch einfällt, ist etwas bezüglich der Initialisierung. Wenn der pointer nicht global initialisiert wird mit volatile uint8_t *port = &PINC; sondern eben nur global deklariert mit volatile uint8_t *port; Wie ist es in diesem Fall (allgemein) mit der Initialisierung? Kann hier grundsätzlich in jeder beliebigen Unterfunktion diese Initialisierung stattfinden(die Variable ist bis zu diesem Zeitpunkt zwar deklariert, besitzt aber noch keinen korrekten Wert/Adresse) oder muss das z.B.: im main.c sein? Gruß Helmut
> Kann hier grundsätzlich in jeder beliebigen Unterfunktion diese > Initialisierung stattfinden(die Variable ist bis zu diesem Zeitpunkt > zwar deklariert, besitzt aber noch keinen korrekten Wert/Adresse) Falsch, sie besitzt einen korrekten Wert: den Nullzeiger. Das ist vom C-Standard abgedeckt, d. h. du darfst dich drauf verlassen. > oder muss das z.B.: im main.c sein? Eine Zuweisung auf ein globales Objekt darf aus jeder beliebigen Funktion heraus erfolgen.
Alles klar, ich habe nun einen dieser Pointer ersetzt durch zwei defines und ein paar kleinen Änderungen im Code, da der eine ziemlich unnötig war... Ansonsten scheint das Programm so zu funktionieren, wenn auch nicht immer....manchmal beginnen die LEDs am Port B zu blinken, obwohl Sie zuvor schon geleuchtet hatten (was signalisieren sollte, dass der taster stabil ist)... Und das, obwohl ich die Interrupts zu diesem Zeitpunkt deaktiviere... Wie auch immer, falls jemand Zeit und Lust hat, kann er ja einen kurzen Blick auf meinen aktuellen Code werfen (im Anhang), vielleicht hab ich noch wo einen Denkfehler... Grüße, Helmut
dein main Programm ist nur zum einmaligen Gebrauch bestimmt: du wartest bis der Taster stabil ist, dann setzt du den Port auf 0, und dann?? Walter
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.