www.mikrocontroller.net

Forum: Compiler & IDEs Zeiger auf Variable


Autor: Chris R. (mrgreen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich steh grad bezüglich eines Zeigers etwas auf dem Schlauch.

Ich habe in einem Array im Flash einen Zeiger auf eine Variable liegen.
Diese will ich dann lesen oder verändern.

uint8_t get_selection(uint8_t id) {
  uint8_t *foo = pgm_read_word(&menu[id].old_selection);
  return *foo;
}

Ändern der Variablen:
void set_selection(uint8_t id, uint8_t value){
  uint8_t *t = pgm_read_word(&menu[id].old_selection);
  *t = value;
}

wobei menu.old_selection vom Typ uint8_t* ist.
Initialisiert habe ich old_selection mit &bar, wobei bar natürlich auch 
uint8_t ist.

So klappt es aber nicht. Aber pgm_read_word liefert mir doch lediglich 
die Adresse der Variablen zurück, auf die menu.old_selection zeigt.
Das muss ich doch dann de-referenzieren, um auf den Inhalt dieser 
Variablen zu kommen??

Gruß
Mr.Green

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In

return *foo;

ist doch deine Dereferenzierung (*), um auf den Inhalt zu kommen.

Du solltest mehr Code angeben: Wie legst du menu[] an, wie speicherst du 
Werte darin und wie willst du die angegebenen Funktionen im späteren 
Code nutzen.

Autor: Chris R. (mrgreen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Menü bau ich aus einem struct auf:

uint8_t sel_on_off; (die ist global, über ein extern)

typedef struct {
  uint8_t id,
    next,
    prev,
    parent,
    child;
    char name[MENU_STRING_LENGTH];
    uint8_t type;
    uint8_t int_part,
      fract_part;
    uint32_t max_int;
    void ( *fkt_pointer )( void );
  uint8_t *old_selection;
  uint32_t *old_int;
  uint16_t *old_fract;

} menu_t;

Menu ist im Flash und logischerweise fest kodiert:
menu_t menu[40] PROGMEM = { [...]
{31,   28,    30,    4,      31,     "LangeAuswahl4",        TYPE_TEXT, 
0, 0, 0, 0 &sel_on_off}};

Auf den Inhalt von sel_on_off will ich dann lesen bzw. schreibend 
zugreifen.
Dazu hatte ich mir die Funktionen oben ausgedacht, die dem Compiler aber 
nicht so recht schmecken wollen.
Das verunsichert mich etwas, weil die doch von der Theorie her so 
funktionieren sollten, oder nicht? Durch das pgm_read_word(...) erhalte 
ich doch erst die Adresse, an der dann der Inhalt von sel_on_off liegt.
Oder ist da ein Denkfehler?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich sehe keinen Denkfehler. Der kann aber noch in dem Code stecken, der 
die Funktionen get_selection() und set_selection() verwendet.

> menu_t menu[40] PROGMEM = { [...]
> {31,   28,    30,    4,      31,     "LangeAuswahl4",        TYPE_TEXT,
> 0, 0, 0, 0 &sel_on_off}};
            ^
Wenn das (^) im Originalcode auch so ist, ist das ein fataler Fehler für 
dein Programm.

Autor: Chris R. (mrgreen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ne da ist natürlich ein Komma.
Da stand ein Funktionszeiger, der für meine Frage aber nicht relevant 
ist :)

Muss ich denn vielleicht noch casten?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simuliert auf dem Atmega8 wie erwartet:

#include <avr/io.h>
#include <inttypes.h>
#include <avr/pgmspace.h>

#define MENU_STRING_LENGTH 32
#define TYPE_TEXT 2

uint8_t sel_on_off;

typedef struct {
  uint8_t id,    next,    prev,    parent,    child;
  char name[MENU_STRING_LENGTH];
  uint8_t type;
  uint8_t int_part, fract_part;
  uint32_t max_int;
  void ( *fkt_pointer )( void );
  uint8_t *old_selection;
  uint32_t *old_int;
  uint16_t *old_fract;
} menu_t;

menu_t menu[2] PROGMEM = { 
  {31, 28, 30, 4, 31, 
   "LangeAuswahl4", 
   TYPE_TEXT, 
   0, 0, 
   0, 
   0, 
   &sel_on_off,
   0,
   0
  }
};

uint8_t get_selection(uint8_t id) {
  uint8_t *foo = (uint8_t *) pgm_read_word(&menu[id].old_selection);
  return *foo;
}

void set_selection(uint8_t id, uint8_t value){
  uint8_t *t = (uint8_t *) pgm_read_word(&menu[id].old_selection);
  *t = value;
}

int main(void)
{
  uint8_t dummy;
  
  sel_on_off = 23;

  dummy = get_selection(0);

  if (dummy == sel_on_off)
    dummy = 1;
  else
    dummy = 0;

  set_selection(0, 42);

  dummy = get_selection(0);

  if (dummy == 42)
    dummy = 1;
  else
    dummy = 0;

  while(1);
}


Der Cast (uint8_t *) beseitigt nur eine Warnung, ist aber an dieser 
Stelle durchaus "legal".

Autor: Chris R. (mrgreen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wow danke für die Arbeit!!
An den Simulator habe ich gar nicht gedacht und mir den Kopf zerbrochen, 
wie ich das testen könnte :/

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.