Verkettete Strukturen, typedefs und Funktionszeiger

#1389355
Lesenswert?

Hallo,

Zuerst einmal der Code...



Das ist eine doppelt verkettete Liste
1
typedef struct EVIS_SCREEN
2
{
3
    struct EVIS_SCREEN *next;
4
    struct EVIS_SCREEN *last;
5
    uint16_t uid;
6
    uint16_t x_pos;
7
    uint16_t y_pos;
8
    uint8_t  priority;
9
    uint8_t *object; // for example EVIS_OBJ_BACKGROUND_T
10
    uint8_t  onscreen;
11
}EVIS_SCREEN_T;

Hier ein entsprechendes Objekt
1
 typedef struct EVIS_OBJ_BACKGROUND
2
{
3
    uint16_t uid;
4
    uint8_t priority;
5
    EVIS_DRAW_FP draw;
6
    EVIS_SPRITE_T sprite;
7
}EVIS_OBJ_BACKGROUND_T;

Das dazugehörige Sprite
1
typedef struct EVIS_SPRITE
2
{
3
    uint16_t size_x;
4
    uint16_t size_y;
5
    uint8_t *sprite;
6
}EVIS_SPRITE_T;

Der Funktionszeiger
1
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
1
void evis_render(uint8_t *fb, EVIS_SCREEN_T *screen)
2
{
3
    while(screen != NULL)
4
        {
5
            screen->object->draw(fb,screen);
6
            screen = screen->next;
7
        }
8
}


Diese Funktion ist dann zum Zeichnen da... Hier als Beispiel die 
Funktion für den Background.
1
EVIS_DRAW_FP *evis_draw_obj_background(uint8_t *fb,uint8_t *element)
2
{
3
    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);
4
}

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
1
eVis\evis\evis.c||In function `evis_render':|
2
eVis\evis\evis.c|145|error: request for member `object' in something not a structure or union|
3
eVis\evis\evis.c||In function `evis_draw_obj_background':|
4
eVis\evis\evis.c|154|error: request for member `object' in something not a structure or union|
5
eVis\evis\evis.c|154|error: request for member `x_pos' in something not a structure or union|
6
eVis\evis\evis.c|154|error: request for member `y_pos' in something not a structure or union|
7
eVis\evis\evis.c|154|error: request for member `object' in something not a structure or union|
8
eVis\evis\evis.c|154|error: request for member `object' in something not a structure or union|
9
||=== Build finished: 6 errors, 4 warnings ===|

Ich bin mir ziemlich sicher das hier ist falsch
1
typedef struct EVIS_SCREEN
2
{
3
    struct EVIS_SCREEN *next;
4
    struct EVIS_SCREEN *last;
5
    uint16_t uid;
6
    uint16_t x_pos;
7
    uint16_t y_pos;
8
    uint8_t  priority;
9
    uint8_t *object; // for example EVIS_OBJ_BACKGROUND_T
10
    uint8_t  onscreen;
11
}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?
#1389429
Lesenswert?

Kannst du mir vielleicht ein Beispiel an der Funktion evis_render(...) 
zeigen?
Ausgehend von
1
typedef struct EVIS_SCREEN
2
{
3
    struct EVIS_SCREEN *next;
4
    struct EVIS_SCREEN *last;
5
    uint16_t uid;
6
    uint16_t x_pos;
7
    uint16_t y_pos;
8
    uint8_t  priority;
9
    void *object; // for example EVIS_OBJ_BACKGROUND_T
10
    uint8_t  onscreen;
11
}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 :(
#1389493
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:
1
(*(EVIS_DRAW_FP*)(screen->object))(fb,screen);
#1389608
Lesenswert?

> Denke das liegt an der Definition vom Funktionspointer...

Die ist in der Tat sehr fragwürdig.
1
typedef int (*EVIS_DRAW_FP)(uint8_t, uint8_t);
Die Parameter sollten ja wohl zwei Pointer sein.
Also eher so:
1
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?
#1389628
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 ;)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren