Frage

Was ist der Zweck des __builtin_offsetof Operators (oder _FOFF Operator in Symbian) in C ++?

Zusätzlich was bedeutet es zurückgeben? Zeiger? Anzahl der Bytes?

War es hilfreich?

Lösung

Es ist ein builtin durch die GCC-Compiler bereitgestellt, um die offsetof Makro zu implementieren, die durch den C- und C ++ Standard vorgeschrieben werden:

GCC - offsetof

Sie gibt den Offset in Bytes, die ein Mitglied einer POD Struktur / Union ist.

Beispiel:

struct abc1 { int a, b, c; };
union abc2 { int a, b, c; };
struct abc3 { abc3() { } int a, b, c; }; // non-POD
union abc4 { abc4() { } int a, b, c; };  // non-POD

assert(offsetof(abc1, a) == 0); // always, because there's no padding before a.
assert(offsetof(abc1, b) == 4); // here, on my system
assert(offsetof(abc2, a) == offsetof(abc2, b)); // (members overlap)
assert(offsetof(abc3, c) == 8); // undefined behavior. GCC outputs warnings
assert(offsetof(abc4, a) == 0); // undefined behavior. GCC outputs warnings

@ Jonathan liefert ein schönes Beispiel dafür, wo Sie es verwenden können. Ich erinnere mich, es gesehen intrusive Listen zu implementieren verwendet (Listen, deren Datenelemente umfassen neben und zurück Zeiger selbst), aber ich kann mich nicht erinnern, wo es hilfreich war es bei der Umsetzung traurig.

Andere Tipps

Als @litb weist darauf hin, und @JesperE zeigt, offsetof () eine ganze Zahl in Bytes (als size_t Wert) Offset bereitstellt.

Wann könnte man es verwenden?

Ein Fall, in dem es von Bedeutung sein könnte, ist ein tabellengesteuerte Betrieb für eine enorme Anzahl verschiedenen Konfigurationsparameter aus einer Datei zu lesen und die Wert in eine ebenso enorme Datenstruktur zu stopfen. Reduzierung der enormen nach unten, so trivial (und eine Vielzahl von notwendigen realen Praktiken zu ignorieren, wie die Definition Strukturtypen in Header), ich meine, dass einige Parameter ganzen Zahlen und andere Zeichenfolgen sein könnte, und der Code könnte schwach wie folgt aussehen:

#include <stddef.h>

typedef stuct config_info config_info;
struct config_info
{
   int parameter1;
   int parameter2;
   int parameter3;
   char *string1;
   char *string2;
   char *string3;
   int parameter4;
} main_configuration;

typedef struct config_desc config_desc;
static const struct config_desc
{
   char *name;
   enum paramtype { PT_INT, PT_STR } type;
   size_t offset;
   int   min_val;
   int   max_val;
   int   max_len;
} desc_configuration[] =
{
    { "GIZMOTRON_RATING", PT_INT, offsetof(config_info, parameter1), 0, 100, 0 },
    { "NECROSIS_FACTOR",  PT_INT, offsetof(config_info, parameter2), -20, +20, 0 },
    { "GILLYWEED_LEAVES", PT_INT, offsetof(config_info, parameter3), 1, 3, 0 },
    { "INFLATION_FACTOR", PT_INT, offsetof(config_info, parameter4), 1000, 10000, 0 },
    { "EXTRA_CONFIG",     PT_STR, offsetof(config_info, string1), 0, 0, 64 },
    { "USER_NAME",        PT_STR, offsetof(config_info, string2), 0, 0, 16 },
    { "GIZMOTRON_LABEL",  PT_STR, offsetof(config_info, string3), 0, 0, 32 },
};

Sie können jetzt eine allgemeine Funktion schreiben, die Zeilen aus der Konfigurationsdatei, verwirft Kommentare und Leerzeilen liest. Er isoliert dann die Parameternamen und sieht, dass in dem desc_configuration Tisch (die Sie vielleicht sortieren, so dass Sie eine binäre Suche tun können - mehr SO Fragen zu beantworten, dass). Wenn es die richtige config_desc Datensatz findet, kann er den Wert übergeben sie und die config_desc Eintritt in eine von zwei Routinen gefunden -. Eine für die Verarbeitung von Zeichenketten, die andere Zahlen für die Verarbeitung von

Der wichtigste Teil dieser Funktionen ist:

static int validate_set_int_config(const config_desc *desc, char *value)
{
    int *data = (int *)((char *)&main_configuration + desc->offset);
    ...
    *data = atoi(value);
    ...
}

static int validate_set_str_config(const config_desc *desc, char *value)
{
    char **data = (char **)((char *)&main_configuration + desc->offset);
    ...
    *data = strdup(value);
    ...
}

Dies vermeidet eine separate Funktion für jedes einzelne Mitglied der Struktur zu schreiben.

Der Zweck eines integrierten in __offsetof Operator ist, dass der Compiler-Anbieter weiterhin eine offsetof () Makro #define, noch hat sie mit Klassen arbeiten, den unären Operator & definieren. Die typische C-Makro-Definition von offsetof () funktionierte nur, wenn (& L-Wert), um die Adresse dieser rvalue zurückgegeben. D. h

#define offsetof(type, member) (int)(&((type *)0)->member) // C definition, not C++
struct CFoo {
    struct Evil {
        int operator&() { return 42; }
    };
    Evil foo;
};
ptrdiff_t t = offsetof(CFoo, foo); // Would call Evil::operator& and return 42

Als @litb, wobei: der Versatz in Bytes eines struct / Klassenmitglied. In C ++ gibt es Fälle, in denen es nicht definiert ist, in dem Fall wird der Compiler beschweren. IIRC, eine Möglichkeit, es zu implementieren (in C, zumindest) zu tun

#define offsetof(type, member) (int)(&((type *)0)->member)

Aber ich bin sicher, es gibt Probleme, aber ich werde darauf zu hinweisen, dass der interessierten Leser überlassen ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top