2010-08-11 9 views
6

¿La forma en que se estructuran las estructuras de C++ está establecida por el estándar, o al menos común en todos los compiladores?¿Cómo se estructuran las estructuras en la memoria en C++?

Tengo una estructura en la que uno de sus miembros debe estar alineado en límites de 16 bytes, y esto sería más fácil si puedo garantizar el orden de los campos.

Además, para las clases no virtuales, ¿la dirección del primer elemento también es probable que sea la dirección de la estructura?

Estoy muy interesado en GCC y MSVS.

+0

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. –

+0

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. –

+0

@Hans: Estamos haciendo la alineación a mano por esa razón. – ngoozeff

Respuesta

12

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.

+0

El bit de reordenamiento parece preocupante. Me encantaría tener una referencia a la parte relevante del estándar para esto. –

+0

Pensé que todos los miembros de una estructura eran públicos por defecto, privados en una clase. –

+0

Sí, lo son. En este caso, los especificadores de acceso son totalmente vacíos en lo que respecta a la especificación del acceso; todavía están permitidos, y como se señaló anteriormente, todavía significan algo, simplemente nada relacionado con la especificación de acceso. –

5

C++ hereda de c la necesidad/deseo de trabajar eficientemente en muchas plataformas, y por lo tanto deja ciertas cosas al compilador. Además de requerir que los elementos aparezcan en el orden especificado, este es uno de ellos.

Pero muchos compiladores son compatibles con #pragma sy opciones que le permiten establecer el control del embalaje. Vea la documentación de su compilador.

+0

Pero, ¿qué pasa con los requisitos de ABI? Seguramente los compiladores que usan el mismo ABI deberían tener el mismo diseño de objeto. No es parte del estándar, pero los compiladores generalmente se ajustan a algún estándar ABI. –

+0

@Alex: imagino que eso depende de cuán exigente sea el ABI. Incluso entonces necesita la opción de romper las reglas de interoperabilidad con * otros * sistemas. – dmckee

4

es la forma estructuras de C++ se disponen establecido por la norma, o al menos común a través de los compiladores?

No hay garantía en la norma. Yo no dependerá de los compiladores tienen la misma alineación

tengo una estructura donde uno de sus miembros tiene que estar alineado en 16 bytes límites, y esto sería más fácil si puedo garantizar el ordenamiento de la campos.

Los compiladores no cambiarán el orden de los campos.

Éstos son algunos enlaces en forma de introducirlos tanto para GCC y MSVC:
Para GCC: http://developer.apple.com/mac/library/documentation/DeveloperTools/gcc-4.0.1/gcc/Structure_002dPacking-Pragmas.html
MSVC: http://msdn.microsoft.com/en-us/library/ms253935(VS.80).aspx y http://msdn.microsoft.com/en-us/library/2e70t5y1(VS.80).aspx

Me gustaría mantener como estructuras y utilizar un extern "C" para Asegúrate de que funcione correctamente. Tal vez no sea necesario, pero eso definitivamente funcionaría.

0

Las estructuras se disponen secuencialmente en la memoria. Sin embargo, la forma en que están alineados en la memoria varía según el sistema operativo.

Para cosas mayores de 4 bytes, existe una diferencia entre Windows y Linux. Linux los alinea como si fueran 4 bytes, por lo que un doble (8 bytes) podría comenzar en p + 4, p + 8, p + 12, etc. donde p es el inicio de la estructura. En Windows, un doble (8 bytes) necesita comenzar en una dirección que es un múltiplo de 8, por lo que p + 8, p + 16, p + 24, etc.

+0

Eso no está determinado por el sistema operativo, sino principalmente por la arquitectura de la CPU y el compilador. – wallyk

+0

¿Qué te hace pensar que, por curiosidad? El libro de texto para mi clase de sistemas de computación de la universidad dice lo contrario (Computer Systems: A Programmer's Perspective, por Bryant & O'Hallaron). Por lo que yo sé, incluso cuando compilas usando g ++ en cygwin se comporta de manera diferente a g ++ en Linux. –

+0

Es un poco de ambos. El hardware pone un requisito mínimo en todo, pero siempre puedes elegir ser más estricto. Si MS eligiera hacerlo, entonces gcc en Windows no tendría más remedio que hacer lo mismo. –

2

C struct s (y C++ POD, para compatibilidad) are required by the standard to have sequential layout.

La única diferencia entre los compiladores es la alineación, pero afortunadamente, tanto MSVC como GCC admiten #pragma pack.

+0

@ Dan04: vea mi respuesta, aunque ciertamente el comité * pretendía * que los POD tuvieran este requisito, se pasó por alto un extraño caso de esquina, por lo que el requisito no se aplica a todos los tipos de POD. –

+0

@jerry: Sería útil si pudiera proporcionar algún tipo de referencia a este "extraño caso de esquina" en beneficio del resto de nosotros. – Arafangion

+0

@Arafangion: ver mi respuesta editada. –

1

Si desea ver el diseño de la memoria de todos los tipos de clases en la memoria en MSVC, agregue el /d1reportAllClassLayout cambie a la línea de comandos del compilador.

Si desea ver cómo se explica una clase, agregue /d1reportSingleClassLayoutNNNNN donde NNNNN es el nombre de la clase.

Cuestiones relacionadas