2016-02-01 4 views
22

Was macht ((struct name *) 0) -> member) in C?Was macht ((struct name *) 0) -> member) in C?

Die eigentliche C-Anweisung ich dies über gekommen war:

(char *) &((struct name *)0)->member) 
+3

[So] (https://stackoverflow.com/questions/7180290/how-do-you-use-offsetof-on-a-struct), [viele] (https: // stackoverflow.com/questions/713963/why-does-this-Implementierung-of-offsetof-work), [Duplikate] (https://stackoverflow.com/questions/6700114/portability-of-using-stddef-hs-offsetof-rather -als-selbst rollen-). – 2501

+1

Und sein (undefiniertes) Verhalten: https://StackOverflow.com/Questions/26906621/does-Struct-Name-Null-B-Cause-undefined-behaviour-in-C11 – 2501

+0

Ich bin nicht wirklich auf der Suche nach Offsetof zu lernen() Hier. Ich bin speziell daran interessiert zu wissen, wie die gegebene Aussage funktioniert. Es ist kein Duplikat IMHO – krisharav

Antwort

25

Dies ist ein Trick, um den Offset von struct Mitglied member genannt zu bekommen. Die Idee hinter diesem Ansatz besteht darin, dass der Compiler die Adresse member berechnet, wobei angenommen wird, dass sich die Struktur selbst an der Adresse Null befindet.

offsetof Verwendung bietet eine besser lesbare Alternative zu dieser Syntax:

size_t offset = offsetof(struct name, member); 
+0

nett! Danke für den Hinweis auf die Wiki-Seite. das erschien nicht auf Google :) – krisharav

+1

Aber ist es nicht undefiniertes Verhalten, einen Nullzeiger zu dereferenzieren? –

+3

Sie referenzieren es tatsächlich nicht. Nur die Adressen zu erhalten. – krisharav

5

(struct name *)00 wirft auf struct name auf Zeiger.
&((struct name *)0)->member) erhält die Adresse des Mitglieds member.
(char *) &((struct name *)0)->member) überträgt diese Adresse an char *.

Falls jemand denkt, dass der obige Ausdruck einen NULL Zeiger dereferenziert, dann beachten Sie, dass es hier keine Dereferenzierung gibt. Es ist alles für die Adresse des Mitglieds number.

+0

Ist '(struct name *) 0' das gleiche wie' & struct name + 0'? –

+2

@CoolGuy - nein, weil '& struct name' nicht legal C ist, da die Adresse eines Typs nicht übernommen werden kann. – LThode

+0

Wie wird "0" zu etwas Legalem? '0' ist eine Ganzzahl, kein Null-Bit, oder? Sie können einfach '0' oder' 7' oder '\ n''zu Random-Struct-Zeigern umwandeln? – user1717828

5

(struct name*)0 gibt Ihnen eine Struktur Zeiger.

((struct name*)0)->member gibt Ihnen das Mitglied der Struktur, auf die der Zeiger zeigt.

Hinzufügen & gibt Ihnen die Adresse des Mitglieds, und schließlich

(char *) ist die erhaltene Adresse an einen char Zeiger zu werfen.

1

Auf vielen Compilern, wird der obige Ausdruck einen char* ergeben, das, während es kein gültiger Zeiger ist, eine eine oder beide der folgenden Eigenschaften:

  1. Casting den Zeiger direkt auf eine ganze Zahl Typ wird die Verschiebung des angegebenen Elements innerhalb der Struktur ergeben.

  2. Die Subtraktion (char*)0 vom Zeiger ergibt die Verschiebung des angegebenen Elements innerhalb der Struktur.

Beachten Sie, dass die C-Norm keine Anforderungen hinsichtlich erlegt, was geschehen kann, wenn Code einen ungültigen Zeigerwert über die obigen Mittel oder jede andere Form, auch wenn der Code nicht versucht, auf den Zeiger dereferenzieren. Während viele Compiler Zeiger mit den angegebenen Eigenschaften erzeugen, ist ein solches Verhalten nicht universell. Sogar auf Plattformen, auf denen eine klare natürliche Beziehung zwischen Zeigern und ganzen Zahlen besteht, könnten manche Compiler-Hersteller entscheiden, dass sich Programme so verhalten, wie dies durch eine solche Beziehung impliziert ist. Stattdessen wäre es effizienter, den Compiler davon auszugehen, dass ein Programm niemals funktioniert Empfangen von Eingängen, die die Erzeugung von ungültigen Zeigern verursachen würden, und folglich würde jeder Code, der nur relevant wäre, wenn solche Eingaben empfangen würden, weggelassen werden.