2012-02-22 10 views
7

Consideremos el siguiente código:¿Por qué GCC asigna espacio de pila separado para las uniones locales en diferentes ámbitos?

#include <stdlib.h> 

#ifndef TRY 
#define TRY struct 
#endif 

TRY testme 
{ 
    int one; 
    int two; 
    char three; 
    int four; 
}; 

int 
main (void) 
{ 
    { 
    volatile TRY testme one; 

    one.one = 2; 
    one.three = 7; 
    } 

    { 
    volatile TRY testme twos; 

    twos.one = 3; 
    } 

    { 
    volatile TRY testme one; 

    one.one = 4; 
    } 

    { 
    volatile TRY testme twos; 

    twos.one = 5; 
    } 

    { 
    volatile TRY testme twos; 

    twos.one = 6; 
    } 

    { 
    volatile TRY testme twos; 

    twos.one = 6; 
    } 

    return EXIT_SUCCESS; 
} 

Compilado como está para x86 es (que significa testme es un struct), el tamaño de la pila el compilador asigna para principal es de 16 bytes.

$ gcc -g -O2 test.c -o test 
$ objdump -d ./test | ./checkstack.pl i386 | grep main 
16 main 

Sin embargo, compilado con TRY definido a la unión (es decir, testme es una unión), el tamaño de la pila el compilador asigna para principal es de 32 bytes:

$ gcc -DTRY=union -g -O2 test.c -o test 
$ objdump -d ./test | ./checkstack.pl i386 | grep main 

Por otra parte, todas las instancias adicionales de la struct/unión definida en ámbitos adicionales, producirá asignaciones de pila más grandes cuando se usa una unión, pero no ampliará la asignación de pila cuando se utiliza como una estructura.

Ahora bien, esto no tiene sentido - la unión debe tener menos espacio de pila, en todo caso, no más, a continuación, una estructura con los mismos campos!

Parece como si GCC trata a los sindicatos como usar al mismo tiempo, incluso cuando en distintos ámbitos, pero no hace lo mismo para estructuras.

Algunas aclaraciones más:

  1. volátil se utiliza para detener el compilador de optimización de las asignaciones de distancia. Perder lo volátil y compilar sin optimización produce los mismos resultados.

  2. Incluso si testme es una estructura que tiene una unión como uno de los miembros, se observa el mismo comportamiento. En otras palabras, es suficiente que uno de los miembros de una estructura sea una unión para GCC para asignaciones de pila separadas.

  3. El compilador es gcc versión 4.4.3 (Ubuntu 4.4.3-4ubuntu5) pero otras versiones de GCC para otras arquitecturas mostraron el mismo comportamiento.

  4. checkstack.pl simplemente busca en la salida objdump de las instrucciones utilizadas para asignar pila (sub al puntero de pila).

Mi pregunta:

  1. ¿Por qué GCC hacer esto? ¿Es esto un error o hay una razón para este comportamiento?
  2. Asumiendo que esto no es un error, es una Hay una manera de evitar esto y obligar a GCC para asignar pila para stucts mismos como los sindicatos.

Aclaración: Mi pregunta no es por qué la estructura o unión parece ser más grandes en tamaño por el tamaño de su parte. Entiendo que la razón es el relleno para la alineación. Mi problema es que el compilador asigna múltiples marcos de pila para diferentes instancias de la unión a pesar de que están definidos en diferentes ámbitos, mientras que no debería y no hace lo mismo para una estructura con los mismos campos.

Gracias!

+0

Tal vez los sindicatos no están tan bien optimizado en '-O2' (todavía)? Eche un vistazo al código ensamblador generado. También intente deshabilitar 'strict-aliasing'. Ah, y prueba un GCC actual. –

+1

Ha echado un vistazo a [esta pregunta] (http://stackoverflow.com/questions/8453881/sizeof-union-larger-than-expected-how-does-type-alignment-take-place-here) y [ este]] (http://stackoverflow.com/questions/7212585/why-is-my-unions-size-bigger-than-i-expected)? Parece ser una cuestión de restricciones de relleno y alineación – Coren

+0

@ Anony-Mousse -fno-strict-aliasing produce los mismos resultados. Estoy construyendo el último GCC para probar. – gby

Respuesta

8

Al parecer, al menos se ha intentado relajar la paranoia de aliasing estricta de gcc con respecto a los sindicatos.

Es posible que desee asegurarse de que la fuente de gcc compila a partir ha aplicado este parche o equivalente: http://codereview.appspot.com/4444051/

+0

Eso es exactamente lo que estaba buscando. Muchas gracias :-) – gby

0

Es parece mater de relleno y definición básica tamaño predeterminado de la Int.

En 32 bits del mapa de memoria será: uno (2 bytes) Dos (2 bytes) Tres (1 byte) (1 bytes) de relleno cuatro (2 bytes)

total - 8 bytes.

en 64 bits que será: One (4 bytes) dos (4 bytes) Tres (1 byte) (3 bytes de relleno) cuatro (4 bytes)

totales - 16 bytes.

Si cambia "int" a "short int", la memoria se verá diferente.

+1

Pero como una 'unión', todo debería tomar solo 4 bytes, sin importar si son 32 o 64 bits. –

+0

No tengo problemas con la cantidad de una estructura o unión. Mi problema es que GCC parece asignar diferente espacio de pila para diferentes instancias de la unión definida en diferentes ámbitos, aunque no necesita hacer eso y, de hecho, no hace eso para struct – gby

+0

. Incluso como unión, depende de lo que viene a continuación. si está dentro de la matriz de la unión, tomará los 32 bits incluso por debajo de 64 bits.si es variable, entonces en sistemas de 64 bits se ajustará a 64 bits. No es el alcance, es "lo que viene después". –

Cuestiones relacionadas