Forum: Compiler & IDEs Verkettete Strukturen, typedefs und Funktionszeiger


von Michael B. (bubi)


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?

von P. S. (Gast)


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.

von Michael B. (bubi)


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...

von P. S. (Gast)


Lesenswert?

Dann nimm void* als Parameter und caste es in deiner Funktion zurecht.

von Michael B. (bubi)


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 :(

von Stefan E. (sternst)


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);

von Michael B. (bubi)


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!

von Stefan E. (sternst)


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?

von Michael B. (bubi)


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 ;)

von Stefan E. (sternst)


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.

von Michael B. (bubi)


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!

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
Noch kein Account? Hier anmelden.