C y C++ ambos garantizan que los campos se presentarán en la memoria en el mismo orden en que los defina.Para C++ eso solo está garantizado para un tipo de POD (todo lo que sería legítimo como C struct [Editar: C89/90 - no, por ejemplo, un C99 VLA] también calificará como POD).
El compilador es libre de insertar relleno entre los miembros y/o al final de la estructura. La mayoría de los compiladores le brindan alguna forma de controlar eso (por ejemplo, #pragma pack(N)
), pero varía de un compilador a otro.
Bueno, hay un caso esquina que no piensan en, donde no está garantizada para un tipo POD - un especificador de acceso rompe la garantía de pedido:
struct x {
int x;
int y;
public:
int z;
};
Este es un tipo de POD, pero el public:
entre y
y z
significa que podrían teóricamente ser reordenados. Sin embargo, estoy bastante seguro de que esto es puramente teórico: no conozco ningún compilador que reordene a los miembros en esta situación (y a menos que la memoria me falle incluso peor de lo habitual hoy, esto se corrige en C++ 0x).
Editar: las partes pertinentes de la norma (al menos la mayoría de ellos) son § 9/4:
A POD-struct es una clase de agregado que no tiene miembros de datos no volátiles de tipo puntero a miembro, no POD-struct, no POD-union (o matriz de tales tipos) o referencia, y no tiene operador de asignación de copias definido por el usuario y ningún destructor definido por el usuario .
y §8.5.1/1:
Un agregado es una matriz o una clase (cláusula 9) sin constructores el usuario declaradas (12.1), no privados o protegidos no miembros de datos estáticos (cláusula 11), sin clases base (cláusula 10) y sin funciones virtuales (10.3).
y §9.2/12:
... el orden de asignación de los miembros de datos no estáticos separadas por un acceso-especificador es especificar (11.1).
aunque eso es algo restringido por §9.2/17:
Un puntero a un objeto de POD-struct, adecuadamente convertidos utilizando un reinterpret_cast, los puntos a su miembro inicial ...
Por lo tanto, (incluso si está precedido por public:
, el primer miembro que defina debe ser el primero en la memoria. Otros miembros separados por public:
especificadores podrían teóricamente reorganizarse.
También debo señalar que hay espacio para la discusión sobre esto. En particular, también hay una regla en el §9.2/14:
Dos POD-struct (cláusula 9) tipos son compatibles diseño-si tienen el mismo número de miembros de datos no estáticos, y miembros de datos no estáticos correspondiente (en orden) han tipos compatible-layout (3,9)
Por lo tanto, si usted tiene algo así como:
struct A {
int x;
public:
int y;
public:
int z;
};
Se requiere que sea compatible con el diseño:
struct B {
int x;
int y;
int z;
};
Estoy bastante seguro de que esto es/era destinada a significa que los miembros de las dos estructuras deben estar dispuestos de la misma manera en la memoria. Dado que el segundo claramente no puede tener sus miembros reorganizados, el primero tampoco debería serlo. Desafortunadamente, el estándar nunca define realmente lo que significa "compatible con el diseño", lo que hace que el argumento sea bastante débil en el mejor de los casos.
Tienes problemas más grandes. La alineación de montón generalmente no es mejor que 8 por ejemplo. __declspec (alinear) y _aligned_malloc() en MSVC. –
Es posible que desee intentar escribir código simple que acceda a todos los miembros de una estructura y ver la salida del ensamblador de su compilador (-S para gcc, si no recuerdo mal) para ver cómo ocurre el acceso. –
@Hans: Estamos haciendo la alineación a mano por esa razón. – ngoozeff