www.mikrocontroller.net

Forum: Compiler & IDEs Pointer Gültigkeitsbereich


Autor: Helmut (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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".

Autor: Helmut (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Helmut (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Helmut (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"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?

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
void *port;

void foo(void *port)
{
   void *port;
   ...
}
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.

Autor: Helmut (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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"?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Helmut (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ok, hier das gesamte Programm, kompilierbar mit avr-gcc (GCC) 3.4.5

Die Frage habe ich als Kommentar neben die betroffene Zeile geschrieben
;-)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.
port = &PINC; //WARUM DARF DIESE ZEILE NICHT GANZ OBEN STEHEN UNTER
              //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:
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.

Autor: Helmut (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Autor: Helmut (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Helmut (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.