Pregunta

Tengo una definición de estructura de prueba de la siguiente manera:

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

Y en algún lugar lo uso de esta manera:

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

Esto funciona correctamente en mi Windows: imprime 15 como se esperaba, pero ¿es seguro? ¿Puedo estar realmente seguro de que la variable está en el lugar de la memoria que quiero, especialmente en el caso de tales estructuras combinadas (por ejemplo, f está en mi compilador la quinta palabra, pero es una sexta variable)?

Si no es así, ¿hay alguna otra forma de manipular los miembros de la estructura directamente sin tener realmente la estructura de la estructura en el código?

¿Fue útil?

Solución

Parece que estás haciendo dos preguntas

¿Es seguro tratar y realizar una prueba como una int arrray de 3 longitudes?

Probablemente sea mejor evitar esto. Esta puede ser una acción definida en el estándar de C ++, pero incluso si lo es, es poco probable que todas las personas con las que trabajas entiendan lo que estás haciendo aquí. Creo que esto no es compatible si lee el estándar debido a la posibilidad de rellenar estructuras, pero no estoy seguro.

¿Hay una mejor manera de acceder a un miembro sin su nombre?

Sí. Intente usar la offsetof macro / operator. Esto proporcionará el desplazamiento de memoria de un miembro en particular dentro de una estructura y le permitirá ubicar correctamente un punto para ese miembro.

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

Sin embargo, otra forma sería simplemente tomar la dirección de c directamente

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

Otros consejos

No, no puedes estar seguro. El compilador es libre de introducir el relleno entre los miembros de la estructura.

Para agregar a La respuesta de JaredPar , otra opción en C ++ solamente (no en plano C) es crear un objeto puntero a miembro:

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
}

Probablemente esté buscando la macro offsetof . Esto le dará la compensación de bytes del miembro. A continuación, puede manipular el miembro en ese desplazamiento. Tenga en cuenta que esta macro es específica de la implementación. Incluya stddef.h para que funcione.

Probablemente no sea seguro y no se pueda leer al 100%; haciendo así inaceptable ese tipo de código en el código de producción de la vida real.

utilice los métodos establecidos y boost :: bind for create functor que cambiará esta variable.

Aparte de los problemas de relleno / alineación que han surgido otras respuestas, su código viola las reglas estrictas de alias, lo que significa que puede fallar para compilaciones optimizadas (no estoy seguro de cómo MSVC hace esto, pero GCC -O3 romper en este tipo de comportamiento). Esencialmente, dado que test * t y int * ptr son de diferentes tipos, el compilador puede asumir que apuntan a diferentes partes de la memoria y puede reordenar las operaciones.

Considera esta pequeña modificación:

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

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

La salida al final podría ser 13 o 15 , según el orden de operaciones que utilice el compilador.

De acuerdo con el párrafo 9.2.17 de la norma, es de hecho legal lanzar un puntero a una estructura a un puntero a su primer miembro, siempre que la estructura sea POD :

  

Un puntero a un objeto de estructura POD,   adecuadamente convertido utilizando un   reinterpret_cast, apunta a su   miembro inicial (o si ese miembro es un   campo de bits, luego a la unidad en la que   reside) y viceversa. [Nota:   Por lo tanto, podría haber sin nombre   relleno dentro de un objeto POD-struct,   Pero no en su inicio, según sea necesario.   Para lograr una alineación adecuada. ]

Sin embargo, el estándar no ofrece garantías sobre el diseño de las estructuras, incluso las estructuras POD, aparte de que la dirección de un miembro posterior será mayor que la de un miembro anterior, siempre que no haya especificadores de acceso (< código> privado: , protegido: o público: ) entre ellos. Por lo tanto, tratar la parte inicial de su struct test como una matriz de 3 enteros es un comportamiento técnicamente indefinido.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top