Versteht einer die Define's?
-
Das ist die Grundlage;
struct list_head { struct list_head *prev, *next; }; struct io { struct list_head list; int ID; void data; };
und das der defines dazu:
#define list_entry(ptr, type, member) \ ((type *)((char *)(ptr) - (unsigned long)(&((type *)0L)->member)))
hier habe ich noch verstanden, das ich den Pointer des io´s zurückbekomme, in dem der in prt übergebene Pointer liegt. Und funktioniert das auch für Windows? Ist aus einer Linux Version.
Das ist ein For(bedingung) sein, aber wie genau funktioniert das?
#define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member))
Mir platzt gleich der Kopf! wenn jemand das kennt kann er mir das bitte kurz erklären?
-
was uebergibst du als member?
-
im ersten Define wird member list übergeben
in ptr wird der Pointer übergeben der auf die Struktur verweißt(&io->list), die sich in der Struktur (io) befindet. type ist io.
-
ok, dachte ich mir. wollte aber sicher gehen, nicht dass ich hier [edit]nicht[/eidt] bloedsinn rede.
also das ganze ist haesslich... echt haesslich. und doch... naja, irgendwie hat es etwas
der code produziert undefiniertes verhalten laut c standard - aber er duerfte auf den meisten compilern laufen -> garantie gibts aber keine.
zerlegen wir mal schnell das makro:
#define list_entry(ptr, type, member) \ ((type *)((char *)(ptr) - (unsigned long)(&((type *)0L)->member)))
prt ist ein zeiger auf list_head. type der tatsaechliche typ der struct, bei uns io. und member ist der name den list_head in io hat.
soweit nichts aufregendes, jetzt gehts aber los:
der zeiger auf list_head wird als reine adresse betrachtet:
(char *)(ptr)und nun das haessliche:
wir berechnen das offset dass list in io hat. und das subtrahieren wir dann von der adresse auf die ptr zeig.beispiel:
bei io ist das offset von list 0. aber du haettest list auch als letzten member haben koennen, dann waere das offset vermutlich 8 bytes gewesen.die berechnung funktioniert so:
normalerweise berechnet man nen offset so:
(&o->member)-o
also die adresse basis adresse von der adresse von member abziehen -> das liefert die anzahl der bytes die dazwischen liegen.unser problem hier ist: wir kennen die basis adresse aber nicht. wir haben also o nicht. wir greifen zu einem dirty hack:
wir tun so als waere 0 die adresse und tun so als wuerde dort eine io struct liegen:
(type *)0Lund nehmen dann die adresse von list
(&((type *)0L)->member))das ist also o->member
jetzt muessten wir o abziehen - aber das ist ja 0. weil wir adresse 0 angenommen haben. (wir koennten theoretisch auch
(&((type *)10)->member))-10
machen.nun haben wir das offset von list in io.
nun rechen wir einfach list-offset und haben nen zeiger auf die io struktur.
undefiniert ist es deshalb: weil wir mit einem null zeiger hantieren und a->b ja nix anderes als (*a).b ist. aber da wir member ja nicht wirklich ansprechen sondern nur die adresse nehmen, werden es die meisten compiler schlucken...
das foreach makro sollte dann klar sein:
#define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member))
list_entry liefert uns den zeiger auf io wenn wir ihm einen zeiger auf io::list geben.
&pos->member != (head)
ist auch keine magie:
das ganze scheint ein ring zu sein (eine double linked list wo bei last.next==first und first.prev==last ist.)
wir laufen also so lange bis wir wieder am anfang sind.
-
Dieser Thread wurde von Moderator/in rüdiger aus dem Forum Rund um die Programmierung in das Forum ANSI C verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Nightstorm schrieb:
#define list_entry(ptr, type, member) \ ((type *)((char *)(ptr) - (unsigned long)(&((type *)0L)->member)))
hast das mal durch'n compiler gejagt? du wirst dich wundern, was daraus für'n effektiver code wird....
-
Danke Leute, das war meine Vermutung. Eigentlich war ich fast genauso weit, konnte es nur nicht so gut aus drücken. Das ganze stammt aus einer ziehmlich fiesen Libary für USB von Linux, und ich muss das ganze für Windows neu schreiben. Das meiste konnte ich schon zerlegen. Aber das war ich einfach etwas überfordert.
Also nochmal danke. Ween ich die Callbacks besser auseinnander genommen habe, werde ich euch dazu auch nochmal befragen.
-
Hallo, mein Compiler läst mich keinen malloc machen, und ich versteh es nicht (wahrscheinlich stupider Fehler);
#include <windows.h> #include <windowsx.h> #include <stdio.h> #include <stdlib.h> #include "list.h" static struct list_head completions = { completions.prev=&completions , completions.next=&completions}; struct test_io{ struct list_head list; int x; }; int add_io(int index){ struct test_io *t; t = malloc(sizeof(*t)); memset(t, 0, sizeof(*t)); list_add(&t->list,&completions) return 0; }
42 D:\Diplom\VerlinkteListe\main.c invalid conversion from `void*' to `test_io*'
icch verstehe es nicht, kann man das bei c nur in der MAin, habe ich ein Zeichen vergessen und bin Blind?
-
Kann es sein, daß du einen C++ Compiler hast? Unter C ist das afaik legal, aber bei C++ mußt du dem Compiler explizit den richtigen Typ angeben (Cast).
-
du meinst
t=malloc((sizeof(struct test_io));
nö geht leider auch nicht....
Und ich verstehe es nicht, kann ein Neustart helfen?Edit: ist Dev C++ mit default GCC-Compiler
-
nein, ich meinte so etwas:
t = (struct test_io*) malloc(sizeof(struct test_io));
-
danke, jetzt macht er es. Solche zickereien muss man aber erstmal wissen.
Ich währe hier fast amok gelaufen.