Pergunta

Qual é o objetivo do operador __builtin_offsetof (ou operador _FOFF em Symbian) em C ++?

Além disso o que ele voltar? Ponteiro? Número de bytes?

Foi útil?

Solução

É um builtin fornecido pelo compilador GCC para implementar a macro offsetof que é especificado pelo padrão C ++ e C:

GCC - offsetof

Ele retorna o deslocamento em bytes que um membro de um POD struct / união está.

Amostra:

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 fornece um bom exemplo de onde você pode usá-lo. Lembro-me de tê-lo visto usado para implementar listas intrusivas (listas cujos itens de dados incluem next e prev-se ponteiros), mas eu não consigo me lembrar onde ele foi útil para implementá-lo, infelizmente.

Outras dicas

AS @ litb pontos fora e @JesperE mostra, offsetof () fornece um deslocamento em bytes inteiro (como um valor size_t).

Quando você pode usá-lo?

Um caso em que pode ser relevante é uma operação baseada em tabelas para a leitura de um número enorme de parâmetros de configuração diferentes a partir de um arquivo e enchendo os valores em uma estrutura de dados igualmente enorme. Reduzir enorme para baixo para tão trivial (e ignorando uma grande variedade de necessárias práticas do mundo real, tais como a definição de tipos de estrutura nos cabeçalhos), quero dizer que algumas variáveis ??podem ser inteiros e outras cordas, eo código pode parecer levemente como:

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

Agora você pode escrever uma função geral que lê linhas do arquivo de configuração, descartando comentários e linhas em branco. Em seguida, ele isola o nome do parâmetro, e olha que na tabela de desc_configuration (que você pode tipo de modo que você pode fazer uma busca binária - questões de múltipla SO endereço que). Quando encontra o registro config_desc correta, ele pode passar o valor que ele encontrou ea entrada config_desc a uma das duas rotinas -. Um para cordas de processamento, o outro para o processamento de números inteiros

A parte fundamental dessas funções é:

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

Isso evita ter de escrever uma função separada para cada membro separado da estrutura.

O propósito de um built-in __offsetof operador é que o fornecedor compilador pode continuar a #define uma macro offsetof (), ainda têm que trabalhar com classes que definem operador unário &. A definição de macro C típico de offsetof () só funcionou quando (e lvalue) devolveu o endereço dessa rvalue. Ou seja,

#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

Como @ litb, disse: o deslocamento em bytes de um membro struct / classe. Em C ++, existem casos em que é indefinido, no caso do compilador se queixam. IIRC, uma maneira de implementá-lo (em C, pelo menos) é fazer

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

Mas estou certo de que há problemas que isso, mas vou deixar isso para o leitor interessado em apontar ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top