Noté algo extraño después de compilar este código en mi máquina:
#include <stdio.h>
int main()
{
printf("Hello, World!\n");
int a,b,c,d;
int e,f,g;
long int h;
printf("The addresses are:\n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x",
&a,&b,&c,&d,&e,&f,&g,&h);
return 0;
}
El resultado es el siguiente. Observe que entre cada dirección int hay una diferencia de 4 bytes. Sin embargo, entre el último int y el int largo hay una diferencia de 12 bytes:
Hello, World!
The addresses are:
da54dcac
da54dca8
da54dca4
da54dca0
da54dc9c
da54dc98
da54dc94
da54dc88
int
despuésh
en el código fuente. El compilador puede ponerlo en el vacío, antesh
.sizeof
función para eso.printf("size: %d ", sizeof(long));
%x
. Afortunadamente para ti, funciona correctamente en tu plataforma para pasar argumentos de puntero con una cadena de formato esperadaunsigned int
, pero los punteros y las entradas son de diferentes tamaños en muchas ABI. Úselo%p
para imprimir punteros en código portátil. (Es fácil imaginar un sistema en el que su código imprima las mitades superior / inferior de los primeros 4 punteros, en lugar de la mitad inferior de los 8).%zu
. @yoyo_fun para imprimir el uso de direcciones%p
. El uso del especificador de formato incorrecto invoca un comportamiento indefinidoRespuestas:
No tomó 12 bytes, solo tomó 8. Sin embargo, la alineación predeterminada para una longitud int de 8 bytes en esta plataforma es de 8 bytes. Como tal, el compilador necesitaba mover el int largo a una dirección que es divisible por 8. La dirección "obvia", da54dc8c, no es divisible por 8, de ahí el espacio de 12 bytes.
Deberías poder probar esto. Si agrega otro int antes del largo, entonces hay 8 de ellos, debería encontrar que el int largo se alineará bien sin un movimiento. Ahora serán solo 8 bytes de la dirección anterior.
Probablemente valga la pena señalar que, aunque esta prueba debería funcionar, no debe confiar en las variables que se organizan de esta manera. El compilador de AC puede hacer todo tipo de cosas funky para intentar que su programa se ejecute rápidamente, incluidas las variables de reordenamiento (con algunas advertencias).
fuente
Esto se debe a que su compilador está generando relleno adicional entre las variables para garantizar que estén alineadas correctamente en la memoria.
En la mayoría de los procesadores modernos, si un valor tiene una dirección que es un múltiplo de su tamaño, es más eficiente acceder a él. Si se hubiera colocado
h
en el primer lugar disponible, su dirección habría sido 0xda54dc8c, que no es un múltiplo de 8, por lo que habría sido menos eficiente de usar. El compilador sabe sobre esto y está agregando un poco de espacio no utilizado entre sus dos últimas variables para asegurarse de que suceda.fuente
Su prueba no necesariamente prueba lo que cree que es, porque no hay ningún requisito del idioma para relacionar la dirección de cualquiera de estas variables locales entre sí.
Tendría que ponerlos como campos en una estructura para poder inferir algo sobre la asignación de almacenamiento.
No se requiere que las variables locales compartan el almacenamiento uno al lado del otro de ninguna manera en particular. El compilador puede insertar una variable temporal en cualquier lugar dentro de la pila, por ejemplo, que podría estar entre dos de estas variables locales.
Por el contrario, no se permitiría insertar una variable temporal en una estructura, por lo que si imprimiera las direcciones de los campos de estructura en su lugar, estaría comparando los elementos destinados asignados desde el mismo plato lógico de memoria (la estructura).
fuente