Wie funktioniert das C offsetof-Makro? [Duplikat]

8
  

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?

    
Samuel Liew 26.10.2011, 01:47
quelle

4 Antworten

12

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:

%Vor%

, mit dem Sie programmatisch die Felder von struct foo nach Namen füllen können, z. beim Lesen einer JSON-Datei.

    
R.. 26.10.2011, 01:55
quelle
24

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

  1. Wirf den Wert null auf den Struktur-Pointer-Typ a*
  2. Abrufen des struct-Feldes b dieses (illegal platzierten) struct-Objekts
  3. Abrufen der Adresse dieses b -Feldes
  4. Übertragung der Adresse an ein 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.

    
Eamonn O'Brien-Strain 26.10.2011 02:15
quelle
4

Es wird der Byte-Offset eines bestimmten Mitglieds eines struct gefunden. Zum Beispiel, wenn Sie die folgende Struktur hätten:

%Vor%

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.

    
Adam Rosenfield 26.10.2011 01:58
quelle
-2

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

    
Adrian Cornish 26.10.2011 02:26
quelle

Tags und Links