Percebi algo estranho depois de compilar esse código na minha 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;
}
O resultado é o seguinte. Observe que entre todos os endereços int há uma diferença de 4 bytes. No entanto, entre o último int e o int longo, há uma diferença de 12 bytes:
Hello, World!
The addresses are:
da54dcac
da54dca8
da54dca4
da54dca0
da54dc9c
da54dc98
da54dc94
da54dc88
int
depoish
no código fonte. O compilador pode colocá-lo na lacuna, antesh
.sizeof
função para isso.printf("size: %d ", sizeof(long));
%x
. Para sua sorte, acontece que funcione corretamente em sua plataforma para passar argumentos de ponteiro com uma sequência de formatounsigned int
esperada, mas ponteiros e ints são de tamanhos diferentes em muitas ABIs. Use%p
para imprimir ponteiros em código portátil. (É fácil imaginar um sistema em que o código seria imprimir superior / metades inferiores das primeiras 4 ponteiros, em vez de metade inferior de todos os 8.)%zu
. @yoyo_fun para imprimir endereços de uso%p
. Usando o especificador formato errado invoca um comportamento indefinidoRespostas:
Não demorou 12 bytes, apenas oito. No entanto, o alinhamento padrão para um int de 8 bytes nesta plataforma é de 8 bytes. Como tal, o compilador precisava mover o int longo para um endereço divisível por 8. O endereço "óbvio", da54dc8c, não é divisível por 8, daí a diferença de 12 bytes.
Você deve poder testar isso. Se você adicionar outro int antes do long, então existem 8 deles, deverá achar que o int longo estará alinhado ok sem movimento. Agora serão apenas 8 bytes do endereço anterior.
Provavelmente vale ressaltar que, embora esse teste deva funcionar, você não deve confiar nas variáveis que estão sendo organizadas dessa maneira. É permitido ao compilador AC fazer todo tipo de coisas estranhas para tentar executar seu programa rapidamente, incluindo reordenar variáveis (com algumas ressalvas).
fonte
Isso ocorre porque seu compilador está gerando preenchimento extra entre variáveis para garantir que elas estejam alinhadas corretamente na memória.
Na maioria dos processadores modernos, se um valor tiver um endereço múltiplo de seu tamanho, será mais eficiente acessá-lo. Se tivesse colocado
h
no primeiro local disponível, seu endereço seria 0xda54dc8c, que não é múltiplo de 8, portanto seria menos eficiente de usar. O compilador sabe disso e está adicionando um pouco de espaço não utilizado entre as duas últimas variáveis para garantir que isso aconteça.fonte
Seu teste não está necessariamente testando o que você pensa que é, porque não há requisito do idioma para relacionar o endereço de qualquer uma dessas variáveis locais entre si.
Você precisaria colocá-los como campos em uma estrutura para poder deduzir algo sobre a alocação de armazenamento.
Variáveis locais não são necessárias para compartilhar armazenamento próximo umas das outras de qualquer maneira específica. O compilador pode inserir uma variável temporária em qualquer lugar da pilha, por exemplo, que pode estar entre duas dessas variáveis locais.
Por outro lado, não seria permitido inserir uma variável temporária em uma estrutura; portanto, se você imprimisse os endereços dos campos de estrutura, compararia os itens alocados a partir do mesmo bloco de memória lógica (a estrutura).
fonte