Pergunta

Eu tenho uma definição de estrutura de teste da seguinte maneira:

struct test{
    int a, b, c;
    bool d, e;
    int f;
    long g, h;
};

E em algum lugar que eu o uso desta maneira:

test* t = new test;   // create the testing struct
int* ptr = (int*) t;
ptr[2] = 15;          // directly manipulate the third word
cout << t->c;         // look if it really affected the third integer

Isso funciona corretamente nas minhas janelas - imprime 15 como esperado, mas é seguro? Posso ter certeza de que a variável está no local na memória que eu quero que seja - especialmente no caso de tais estruturas combinadas (por exemplo, f está no meu compilador a quinta palavra, mas é uma sexta variável)?

Caso contrário, existe outra maneira de manipular os membros da Struct diretamente sem realmente ter o construto de estrutura no código?

Foi útil?

Solução

Parece que você está fazendo duas perguntas

É seguro tratar e testar como um 3 comprimento int arrray?

Provavelmente é melhor evitar isso. Essa pode ser uma ação definida no padrão C ++, mas mesmo que seja, é improvável que todos com quem você trabalha entenda o que está fazendo aqui. Acredito que isso não é suportado se você ler o padrão devido ao potencial das estruturas de almofada, mas não tenho certeza.

Existe uma maneira melhor de acessar um membro sem seu nome?

Sim. Tente usar o Offsetf macro/operador. Isso fornecerá o deslocamento da memória de um membro específico dentro de uma estrutura e permitirá que você posicione corretamente um ponto para esse membro.

size_t offset = offsetof(mystruct,c);
int* pointerToC = (int*)((char*)&someTest + offset);

Outra maneira, porém, seria apenas tomar o endereço de C diretamente

int* pointerToC = &(someTest->c);

Outras dicas

Não, você não pode ter certeza. O compilador é gratuito para introduzir preenchimento entre os membros da estrutura.

Para adicionar Resposta de Jaredpar, outra opção apenas em C ++ (não na lisão C) é criar um objeto de ponteiro para membro:

struct test
{
  int a, b, c;
  bool d, e;
  int f;
  long g, h;
};

int main(void)
{
  test t1, t2;

  int test::*p;  // declare p as pointing to an int member of test
  p = &test::c;  // p now points to 'c', but it's not associating with an object
  t1->*p = 3;    // sets t1.c to 3
  t2->*p = 4;    // sets t2.c to 4

  p = &test::f;
  t1->*p = 5;    // sets t1.f to 5
  t2->*p = 6;    // sets t2.f to 6
}

Você provavelmente está procurando o offsetof macro. Isso fará com que você o compensará o membro do membro. Você pode manipular o membro nesse deslocamento. Nota Porém, essa macro é específica da implementação. Incluir stddef.h Para fazer isso funcionar.

Provavelmente não é seguro e é 100% não legível; tornando esse tipo de código inaceitável no código de produção da vida real.

Use Métodos Definir e Boost :: Bind for Create Functor, que alterará essa variável.

Além de questões de preenchimento/alinhamento que outras respostas trouxeram, seu código viola regras estritas de alias, o que significa que pode quebrar para construções otimizadas (não tenho certeza de como o MSVC faz isso, mas o GCC -O3 irá quebrar esse tipo de comportamento). Essencialmente, porque test *t e int *ptr são de tipos diferentes, o compilador pode assumir que aponta para diferentes partes da memória e pode reordenar operações.

Considere esta pequena modificação:

test* t = new test;
int* ptr = (int*) t;

t->c = 13;
ptr[2] = 15;
cout << t->c;

A saída no final pode ser 13 ou 15, dependendo da ordem das operações que o compilador usa.

According to paragraph 9.2.17 of the standard, it is in fact legal to cast a pointer-to-struct to a pointer to its first member, providing the struct is POD:

A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [Note: There might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to achieve appropriate alignment. ]

However, the standard makes no guarantees about the layout of structs -- even POD structs -- other than that the address of a later member will be greater than the address of an earlier member, provided there are no access specifiers (private:, protected: or public:) between them. So, treating the initial part of your struct test as an array of 3 integers is technically undefined behaviour.

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