mikrocontroller.net

Forum: Compiler & IDEs Verkettete Strukturen, typedefs und Funktionszeiger


Autor: Michael B. (bubi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Zuerst einmal der Code...



Das ist eine doppelt verkettete Liste
typedef struct EVIS_SCREEN
{
    struct EVIS_SCREEN *next;
    struct EVIS_SCREEN *last;
    uint16_t uid;
    uint16_t x_pos;
    uint16_t y_pos;
    uint8_t  priority;
    uint8_t *object; // for example EVIS_OBJ_BACKGROUND_T
    uint8_t  onscreen;
}EVIS_SCREEN_T;

Hier ein entsprechendes Objekt
 typedef struct EVIS_OBJ_BACKGROUND
{
    uint16_t uid;
    uint8_t priority;
    EVIS_DRAW_FP draw;
    EVIS_SPRITE_T sprite;
}EVIS_OBJ_BACKGROUND_T;

Das dazugehörige Sprite
typedef struct EVIS_SPRITE
{
    uint16_t size_x;
    uint16_t size_y;
    uint8_t *sprite;
}EVIS_SPRITE_T;

Der Funktionszeiger
typedef int (*EVIS_DRAW_FP)(uint8_t, uint8_t);

Das ist die Hauptfunktion. Sie geht Schritt für Schritt durch die Liste 
und ruft den entsprechenden Funktionszeiger mit dem passenden Element 
auf.
Dann geht sie zum nächsten Element
void evis_render(uint8_t *fb, EVIS_SCREEN_T *screen)
{
    while(screen != NULL)
        {
            screen->object->draw(fb,screen);
            screen = screen->next;
        }
}


Diese Funktion ist dann zum Zeichnen da... Hier als Beispiel die 
Funktion für den Background.
EVIS_DRAW_FP *evis_draw_obj_background(uint8_t *fb,uint8_t *element)
{
    EVIS_DRAWSPRITE((uint8_t*) fb, element->object->sprite->sprite, element->x_pos, element->y_pos, element->object->sprite->x_size, element->object->sprite->y_size);
}

Wichtig an dem ganzen ist, das die evis_render nicht wissen muss um 
welches Objekt es sich handelt oder wie man es zeichnet.

Ich bekomme jetzt aber folgende Fehler
eVis\evis\evis.c||In function `evis_render':|
eVis\evis\evis.c|145|error: request for member `object' in something not a structure or union|
eVis\evis\evis.c||In function `evis_draw_obj_background':|
eVis\evis\evis.c|154|error: request for member `object' in something not a structure or union|
eVis\evis\evis.c|154|error: request for member `x_pos' in something not a structure or union|
eVis\evis\evis.c|154|error: request for member `y_pos' in something not a structure or union|
eVis\evis\evis.c|154|error: request for member `object' in something not a structure or union|
eVis\evis\evis.c|154|error: request for member `object' in something not a structure or union|
||=== Build finished: 6 errors, 4 warnings ===|

Ich bin mir ziemlich sicher das hier ist falsch
typedef struct EVIS_SCREEN
{
    struct EVIS_SCREEN *next;
    struct EVIS_SCREEN *last;
    uint16_t uid;
    uint16_t x_pos;
    uint16_t y_pos;
    uint8_t  priority;
    uint8_t *object; // for example EVIS_OBJ_BACKGROUND_T
    uint8_t  onscreen;
}EVIS_SCREEN_T;

uint8_t *object...
Eigentlich müsste ich um dann mit dem -> Operator arbeiten zu können die 
komplette Struktur castet und derefernzieren... Irgendwie stehe ich hier 
aber auf der Leitung :(
Kann mir da wer weiterhelfen?

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Compiler sagt dir doch genau, was falsch ist. Du willst auf einen 
Member von *element zugreifen, das ist aber keine Struktur und keine 
Union - womit er voellig recht hat, es ist ein uint8_t.

Autor: Michael B. (bubi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Richtig...
Funktionieren würde es dann wenn ich schreibe EVIS_OBJ_BACKGROUND_T 
*object;
Nur habe ich dann das Problem das eine Objektdefinition in der Liste 
vorhanden ist, was ich vermeiden möchte/muss...
Deshalb ja meine Frage... Eigentlich müsste ich das Objekt 
dereferenzieren und umcasten...hmm...

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann nimm void* als Parameter und caste es in deiner Funktion zurecht.

Autor: Michael B. (bubi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kannst du mir vielleicht ein Beispiel an der Funktion evis_render(...) 
zeigen?
Ausgehend von
typedef struct EVIS_SCREEN
{
    struct EVIS_SCREEN *next;
    struct EVIS_SCREEN *last;
    uint16_t uid;
    uint16_t x_pos;
    uint16_t y_pos;
    uint8_t  priority;
    void *object; // for example EVIS_OBJ_BACKGROUND_T
    uint8_t  onscreen;
}EVIS_SCREEN_T;

wie kann ich da jetzt auf die Funktion draw(...) zugreifen?
Wenn ich NICHT weiß welchen Typs das Objekt ist? Ich weiß ja "nur" wo 
der Pointer steht, aber ich wüsste gerade nicht wie ich das dem Compiler 
mitgeben soll.. :(
Ich komme leider auch mit Google hier nicht weiter :(

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du meinst, es gibt noch andere Strukturen als EVIS_OBJ_BACKGROUND, auf 
die object zeigen kann? Dann kannst du nur dann unabhängig von der 
konkreten Struktur auf draw zugreifen, wenn draw relativ zum 
Strukturanfang immer die gleiche Position in der Struktur hat, also im 
einfachsten Fall in allen Strukturen an erster Stelle steht. Im Fall von 
"immer an erster Stelle" kannst du dann z.B. *object direkt zum 
Funktionszeiger casten und aufrufen.
Also etwa so:
(*(EVIS_DRAW_FP*)(screen->object))(fb,screen);

Autor: Michael B. (bubi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die Hilfe!
Funktioniert soweit... also der Aufruf zumindest :)
Nur leider wird dem ganzen kein Pointer übergeben... Im Debugger kann 
ich dann die Adresse 0x0,0x0 für *fb und *screen sehn :(
Denke das liegt an der Definition vom Funktionspointer... aber wird auch 
noch werden :)
Dankee nochmal!

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Denke das liegt an der Definition vom Funktionspointer...

Die ist in der Tat sehr fragwürdig.
typedef int (*EVIS_DRAW_FP)(uint8_t, uint8_t);
Die Parameter sollten ja wohl zwei Pointer sein.
Also eher so:
typedef int (*EVIS_DRAW_FP)(uint8_t*,EVIS_SCREEN_T*);
Das uint8_t* ist aber auch anzuweifeln. Aber da weißt nur du, was da 
eigentlich stehen müsste, denn aus dem Code oben geht das nicht hervor.

Und was ist mit dem Rückgabewert? Warum ist eigentlich 
evis_draw_obj_background so definiert, dass es einen Pointer auf einen 
Funktionspointer zurück liefern soll?

Autor: Michael B. (bubi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gut das ich nochmal F5 gedrückt habe vorm posten :)
Also es geht jetzt.. Mir ist es auch gleich aufgefallen das es so nicht 
klappen kann ;) War ein überbleibsel von den vielen versuchen.

Der Rückgabewert ist doch mit int definiert? Oder habe ich da wiede was 
durcheinander gebracht... Mittlerweile schon soviel gelsen und bis jetzt 
noch nie mit Funktionspointern gearbeitet das ich schon leicht verwirrt 
bin heute :)

uint8_t* ist ok... ist der Framebuffer ;)

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael B. schrieb:

> Der Rückgabewert ist doch mit int definiert?

Ja, aber evis_draw_obj_background ist doch eine der Funktionen, auf die 
diese Zeiger zeigen sollen, oder? Und dort ist der Rückgabewert kein 
int.

Autor: Michael B. (bubi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh stimmt :D
Falsche Stelle gekuckt.. naja ist schon zu spät ich lass es lieber für 
heute :D
Vielen Dank für die Hilfe!

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.