Pointer - Struct



  • hi,

    typedef struct foo
    {
    	int i;
    	char s[10];
    	bool b;
    }foo;
    
    void *test(foo *foo1)
    {
    	return &(foo1->s);
    }
    
    int main()
    {
    	foo f1;
    	f1.i = 1;
    	strcpy(f1.s, "Hallo");
    	f1.b = true;
    
    	void *ptr = test(&f1);
    	int offset = offsetof(foo, s);
    	int *j = &((foo*)ptr)->i;
    	j -= offset/sizeof(int);
    	std::cout << *j << std::endl;
    }
    


  • verwendet man manchmal so einen trick? void pointer ueber offset auf member 1 der struct zeigen lassen...



  • Ich kann mich nicht erinnern sowas jemals "gebraucht" zu haben. Zumal das Beispiel doch schon arg konstruiert ist.



  • Das ist recht nützlich wenn man typenunabhängige Datenstrukturen baut. Z.B. eine verkette Liste die kann man schön "zerlegen" indem du anstelle des üblichen

    typedef struct t_node
    {
    	void *data
    	struct t_node *next
    }Node;
    

    soetwas baust

    typedef struct t_link
    {
    	struct t_link *next;
    }Link;
    
    typedef struct t_test
    {
    	Link link;
    	int i;
    
    }Test;
    

    Dann schreibst du deine ganzen Funktionen die dann nur auf den "Links" operieren. Leider hast du dann im Code natürlich fast nur Variablen des Typs Link *bla.
    Wenn du die Linkstruktur wie oben als erstes Element definierst, kannst du problemlos einen Link als eine Teststrukur "reinterpretieren", da die Adresse einer Struktur die Adresse des ersten Elements ist.
    Jedenfalls kann man derartiges ja schnell mal vergessen und es sieht z.B. wie folgt aus.

    typedef struct t_test
    {
    	int i;
    	Link link;
    }Test;
    

    Dann wird das mit dem umcasten nichts und dafür kann man dann dieses eigentümliche Konstrukt mit mit dem Makro offsetof() verwenden, das dann dafür sorgt das du immer die "richtige" Anfangsadresse bekommst.

    In Code könnte das ungefähr wie folgt aussehen.

    int main(void)
    {
    
    	Test a; int off; Link *b; Test *c; void *d;
    
    	a.link.next = NULL;
    	a.i = 10;
    
    	b = &a.link;
        off = offsetof(Test, link);
    
    	d = (char*)b - off;
    	c = d;
    
    	printf("%p \n", &a);
    	printf("%p \n", c);
    	printf("%d \n", c->i);
    return 0;
    }
    

    Natürlich kannst du dir dafür jetzt irgendeine Funktion schreiben die einen void* zurückgibt oder du baust dir ein hübsches #define dafür.
    Wie oben schon erwähnt liegt der Hauptsinn darin das du z.B. Strukturen beliebiger Art verketten kannst indem du nur ein "Link"-Element einfügst.

    tt





  • berechnet das offsetof auch moegliches struct padding mit?



  • Ja, tut es.

    ich hab' mal eine Implementation von offsetof gesehen, die sah ungefähr so aus:

    #define offsetof(typ,mem) (int)&((typ*)NULL->mem)
    


  • ist eigentlich

    bool b
    

    überhaupt ansi c ?

    muss es nicht bei ansi c z.b. "int WahrOderFalsch" heißen ?



  • 'bool' gibt's auch. ist ein #define oder typedef für '_Bool'.
    früher hatte C noch keinen boolean type.
    aber eigentlich ist es egal, kannst auch 'int' nehmen...


Anmelden zum Antworten