qual è lo scopo e il tipo di ritorno dell’operatore __builtin_offsetof?

Qual è lo scopo dell’operatore __builtin_offsetof (o dell’operatore _FOFF in Symbian) in C ++?

Inoltre cosa restituisce? Pointer? Numero di byte?

È un built-in fornito dal compilatore GCC per implementare l’ offsetof macro specificata dallo standard C e C ++:

GCC – offsetof

Restituisce l’offset in byte di un membro di una struttura / unione POD.

Campione:

 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 fornisce un buon esempio di dove puoi usarlo. Ricordo di averlo visto per implementare liste intrusive (elenchi i cui elementi di dati includono i puntatori next e prev), ma non riesco a ricordare dove sia stato utile implementarlo, purtroppo.

Come @litb indica e @JesperE mostra, offsetof () fornisce un offset intero in byte (come valore size_t ).

Quando potresti usarlo?

Un caso in cui potrebbe essere rilevante è un’operazione basata su tabella per leggere un numero enorme di diversi parametri di configurazione da un file e inserire i valori in una struttura di dati altrettanto enorme. Riducendo enormemente a SO banale (e ignorando una vasta gamma di pratiche necessarie nel mondo reale, come la definizione dei tipi di struttura nelle intestazioni), intendo che alcuni parametri potrebbero essere numeri interi e stringhe, e il codice potrebbe apparire vagamente come:

 #include  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 }, }; 

È ora ansible scrivere una funzione generale che legge le righe dal file di configurazione, eliminando i commenti e le righe vuote. Quindi isola il nome del parametro e lo osserva nella tabella desc_configuration (che è ansible ordinare in modo da poter eseguire una ricerca binaria – più domande SO indirizzano quella). Quando trova il record corretto di config_desc , può passare il valore trovato e la voce config_desc a una delle due routine, una per l’elaborazione delle stringhe, l’altra per l’elaborazione degli interi.

La parte fondamentale di queste funzioni è:

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

Questo evita di dover scrivere una funzione separata per ogni membro separato della struttura.

Lo scopo di un operatore __offsetof incorporato è che il fornitore del compilatore possa continuare a # definire una macro offsetof (), ma farlo funzionare con le classi che definiscono l’operatore unario &. La tipica definizione della macro C di offsetof () ha funzionato solo quando (& lvalue) ha restituito l’indirizzo di quel valore. ie

 #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 

Come @litb, ha detto: l’offset in byte di un membro struct / class. In C ++ ci sono casi in cui non è definito, nel caso in cui il compilatore si lamenterà. IIRC, un modo per implementarlo (in C, almeno) è quello di fare

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

Ma sono sicuro che ci sono dei problemi, ma lo lascio al lettore interessato per far notare …