Mögliche Duplikate:
Warum C Code Arbeit?
Wie benutzt man Offsetof ( ) auf einer Struktur?
Ich lese über diesen Offset von Makro im Internet, aber es erklärt nicht, wofür es verwendet wird.
%Vor%Was versucht es zu tun und was ist der Vorteil, es zu benutzen?
Es hat keine Vorteile und sollte nicht verwendet werden, da es undefiniertes Verhalten (und verwendet den falschen Typ - int
anstelle von size_t
).
Der C-Standard definiert ein offsetof
-Makro in stddef.h
, das tatsächlich funktioniert, für Fälle, in denen Sie den Offset eines Elements in einer Struktur benötigen, wie zum Beispiel:
, mit dem Sie programmatisch die Felder von struct foo
nach Namen füllen können, z. beim Lesen einer JSON-Datei.
R .. ist richtig in seiner Antwort auf den zweiten Teil Ihrer Frage: Dieser Code wird nicht empfohlen, wenn Sie einen modernen C-Compiler verwenden.
Aber um den ersten Teil Ihrer Frage zu beantworten, machen Sie Folgendes:
%Vor%Arbeiten von innen nach außen, das ist ...
a*
b
-Feldes int
Vom Konzept her wird ein struct-Objekt auf die Speicheradresse Null gesetzt und dann herausgefunden, wie die Adresse eines bestimmten Feldes ist. Dies könnte Ihnen erlauben, die Offsets im Speicher jedes Felds in einer Struktur herauszufinden, so dass Sie Ihre eigenen Serialisierer und Deserialisierer schreiben können, um Strukturen in und aus Byte-Arrays zu konvertieren.
Natürlich, wenn Sie tatsächlich einen Nullzeiger dereferenzieren würden, würde Ihr Programm abstürzen, aber tatsächlich passiert alles im Compiler und kein tatsächlicher Nullzeiger wird zur Laufzeit dereferenziert.
In den meisten der ursprünglichen Systeme, die C auf der Größe eines int
ausgeführt wurde, war 32 Bits und war das gleiche wie ein Zeiger, so dass dies tatsächlich funktioniert.
Es wird der Byte-Offset eines bestimmten Mitglieds eines struct
gefunden. Zum Beispiel, wenn Sie die folgende Struktur hätten:
Dann hätten Sie offsetOf(MyStruct, d) == 0
, offsetOf(MyStruct, i) == 8
und offsetOf(MyStruct, p) == 12
(das heißt, das Mitglied mit dem Namen d
ist 0 Bytes vom Anfang der Struktur, usw.).
Die Art und Weise, wie es funktioniert, gibt vor, dass eine Instanz Ihrer Struktur an Adresse 0 existiert (der ((a*)(0))
-Teil), und dann nimmt es die Adresse des beabsichtigten Strukturelements und wandelt es in eine ganze Zahl um. Obwohl ein Dereferenzieren eines Objekts an der Adresse 0 normalerweise ein Fehler wäre, ist es in Ordnung, die Adresse zu nehmen, weil sich der Operand der Adresse &
und die Dereferenz des Mitglieds ->
gegenseitig aufheben.
Es wird normalerweise für verallgemeinerte Serialisierungsframeworks verwendet. Wenn Sie Code zum Konvertieren zwischen einer Art von Drahtdaten (z. B. Bytes in einer Datei oder aus dem Netzwerk) und speicherinternen Datenstrukturen haben, ist es oft praktisch, eine Zuordnung von Elementname zu Elementversatz zu erstellen, sodass Sie serialisieren können Deserialisieren von Werten in generischer Weise.
Die Implementierung des Offsets von Makros ist wirklich irrelevant.
Der eigentliche C-Standard definiert es wie in 7.17.3:
%Vor%, das zu einem Ganzzahlkonstantenausdruck mit dem Typ size_t, dessen Wert der Offset in Byte ist, zu dem Strukturelement (bezeichnet von member-designator) vom Anfang seiner Struktur (durch type bezeichnet) expandiert. Der Typ und die Bezeichnung des Elements müssen so sein, dass static type t;
angegeben wird.
Vertraue Adam Rosenfields Antwort.
R ist völlig falsch, und es hat viele Anwendungen - vor allem, wenn es darum geht zu erkennen, wann Code unter Plattformen nicht portabel ist.
(OK, es ist C ++, aber wir verwenden es in statischen Template-Kompilierungszeit-Assertions, um sicherzustellen, dass unsere Datenstrukturen die Größe zwischen Plattformen / Versionen nicht ändern.)