Alvaro: Dúvida sobre pilha. #14

Open
opened 2025-05-26 12:59:34 -03:00 by alvaro · 8 comments

Blau, eu estava assistindo o vídeo da aula 4 e resolvi fazer um programa semelhante ao seu.

Como o seu programa não funcionava como esperado na minha máquina, eu fiz algumas modificações no código.

#include <stdio.h>                                                             
#include <stdlib.h>                                                            
                                                                               
int main(void) {                                                               
                                                                               
    int a = 25;                                                                
    int b = 17;                                                                
    int *p = &b;                                                               
                                                                               
    printf(                                                                    
        "Endereco de a       : %p\n"                                           
        "Valor de a          : %d\n"                                           
        "Endereco em (p - 1) : %p\n"                                           
        "Valor em *(p - 1)   : %d\n"                                           
        "Endereco de b       : %p\n"                                           
        "Valor de b          : %d\n"                                           
        "Endereco em p       : %p\n"                                           
        "Valor em *p         : %d\n"                                           
        "0x%lx + 4 = 0x%lx\n",                                                 
        &a, a, p - 1, *(p - 1), &b, b, p, *p, (long)&a, (long)&a + 4);         
                                                                               
    return EXIT_SUCCESS;                                                       
}                    

A execução do código ficou assim:

alvaro@dinosaur:~/estudo/debxp/cblc_resolucoes/aula04$ gcc aula04d.c
alvaro@dinosaur:~/estudo/debxp/cblc_resolucoes/aula04$ ./a.out 
Endereco de a       : 0x7ffe1b0e3698
Valor de a          : 25
Endereco em (p - 1) : 0x7ffe1b0e3698
Valor em *(p - 1)   : 25
Endereco de b       : 0x7ffe1b0e369c
Valor de b          : 17
Endereco em p       : 0x7ffe1b0e369c
Valor em *p         : 17
0x7ffe1b0e3698 + 4 = 0x7ffe1b0e369c

Para a minha surpresa, na execução do meu programa a variável a ficou alocada 4 bytes abaixo da variável b ao invés de 4 bytes acima.

Daí passou duas coisas pela minha cabeça:

  1. Ou eu fiz algo errado
  2. Ou essa aritmética de ponteiros depende de fatores externos ao código, como:
    • Compilador
    • Sistema operacional
    • Arquitetura

Se a segunda hipótese for válida, a aritmética de ponteiros pode comprometer a portabilidade do programa.

É isso mesmo?

Blau, eu estava assistindo o vídeo da aula 4 e resolvi fazer um programa semelhante ao seu. <img src="/attachments/2535b704-2e7e-4b77-9f72-50664a39e33b" width="600"> Como o seu programa não funcionava como esperado na minha máquina, eu fiz algumas modificações no código. ```c #include <stdio.h> #include <stdlib.h> int main(void) { int a = 25; int b = 17; int *p = &b; printf( "Endereco de a : %p\n" "Valor de a : %d\n" "Endereco em (p - 1) : %p\n" "Valor em *(p - 1) : %d\n" "Endereco de b : %p\n" "Valor de b : %d\n" "Endereco em p : %p\n" "Valor em *p : %d\n" "0x%lx + 4 = 0x%lx\n", &a, a, p - 1, *(p - 1), &b, b, p, *p, (long)&a, (long)&a + 4); return EXIT_SUCCESS; } ``` A execução do código ficou assim: ```bash alvaro@dinosaur:~/estudo/debxp/cblc_resolucoes/aula04$ gcc aula04d.c alvaro@dinosaur:~/estudo/debxp/cblc_resolucoes/aula04$ ./a.out Endereco de a : 0x7ffe1b0e3698 Valor de a : 25 Endereco em (p - 1) : 0x7ffe1b0e3698 Valor em *(p - 1) : 25 Endereco de b : 0x7ffe1b0e369c Valor de b : 17 Endereco em p : 0x7ffe1b0e369c Valor em *p : 17 0x7ffe1b0e3698 + 4 = 0x7ffe1b0e369c ``` Para a minha surpresa, na execução do meu programa a variável `a` ficou alocada 4 bytes **abaixo** da variável `b` ao invés de 4 bytes acima. Daí passou duas coisas pela minha cabeça: 1. Ou eu fiz algo errado 2. Ou essa aritmética de ponteiros depende de fatores externos ao código, como: - Compilador - Sistema operacional - Arquitetura Se a segunda hipótese for válida, a aritmética de ponteiros pode comprometer a portabilidade do programa. É isso mesmo?
198 KiB
Owner

@alvaro wrote in #14 (comment):

Daí passou duas coisas pela minha cabeça:

1. Ou eu fiz algo errado

2. Ou essa aritmética de ponteiros depende de fatores externos ao código, como:
   
   * Compilador
   * Sistema operacional
   * Arquitetura

Se a segunda hipótese for válida, a aritmética de ponteiros pode comprometer a portabilidade do programa.

Se você compilou no Windows, a pilha deles cresce para cima, ao contrário do que acontece em sistemas Unix-like, como o GNU/Linux. Neste caso, sim, a aritmética tem que ser invertida se você estiver lidando com endereços genéricos na pilha. Mas, como veremos na aula de hoje (aula 6), a aritmética não muda com dados em estruturas contínuas, como vetores.

@alvaro wrote in https://bolha.dev/blau_araujo/cblc/issues/14#issue-14: > Daí passou duas coisas pela minha cabeça: > > 1. Ou eu fiz algo errado > > 2. Ou essa aritmética de ponteiros depende de fatores externos ao código, como: > > * Compilador > * Sistema operacional > * Arquitetura > > > Se a segunda hipótese for válida, a aritmética de ponteiros pode comprometer a portabilidade do programa. Se você compilou no Windows, a pilha deles cresce para cima, ao contrário do que acontece em sistemas Unix-like, como o GNU/Linux. Neste caso, sim, a aritmética tem que ser invertida se você estiver lidando com endereços genéricos na pilha. Mas, como veremos na aula de hoje (aula 6), a aritmética não muda com dados em estruturas contínuas, como vetores.
Author

Eu compilei no Ubuntu.

Eu compilei no Ubuntu.
Owner

@alvaro wrote in #14 (comment):

Eu compilei no Ubuntu.

No Ubuntu mesmo ou no Ubuntu do WSL?

@alvaro wrote in https://bolha.dev/blau_araujo/cblc/issues/14#issuecomment-7: > Eu compilei no Ubuntu. No Ubuntu mesmo ou no Ubuntu do WSL?
Author

Ubuntu 24.04.2 LTS

Ubuntu 24.04.2 LTS
Owner

@alvaro wrote in #14 (comment):

Ubuntu 24.04.2 LTS

Acho melhor você passar mais detalhes a cada mensagem, evitando conversar como se fosse um chat. Por exemplo, como você compilou, qual é a sua versão do compilador e qual é a arquitetura do seu sistema?

As especificações da linguagem C não determinam a ordem em que as variáveis são incluídas no quadro de pilha da função. O gcc, no Linux x86_64, inclui na ordem em que elas são escritas no código, resultando em endereços mais baixos porque é a direção de crescimento da pilha em sistemas Unix-like. Mas este não é um comportamento universalmente garantido.

@alvaro wrote in https://bolha.dev/blau_araujo/cblc/issues/14#issuecomment-9: > Ubuntu 24.04.2 LTS Acho melhor você passar mais detalhes a cada mensagem, evitando conversar como se fosse um chat. Por exemplo, como você compilou, qual é a sua versão do compilador e qual é a arquitetura do seu sistema? As especificações da linguagem C não determinam a ordem em que as variáveis são incluídas no quadro de pilha da função. O gcc, no Linux x86_64, inclui na ordem em que elas são escritas no código, resultando em endereços mais baixos porque é a direção de crescimento da pilha em sistemas Unix-like. Mas este não é um comportamento universalmente garantido.
Author

Obrigado, Blau.

Obrigado, Blau.
Owner

Eu testei o seu código no meu sistema (copiado e colado daqui) e tive os resultados esperados originalmente:

blau@xeon:[~/git/cblc/aulas/04-variaveis] (main)
$ gcc var5.c
blau@xeon:[~/git/cblc/aulas/04-variaveis] (main)
$ ./a.out
Endereco de a       : 0x7ffda3bb5374   <--A no endereço mais alto...
Valor de a          : 25
Endereco em (p - 1) : 0x7ffda3bb536c
Valor em *(p - 1)   : 32662
Endereco de b       : 0x7ffda3bb5370 <-- B no endereço mais baixo...
Valor de b          : 17
Endereco em p       : 0x7ffda3bb5370
Valor em *p         : 17
0x7ffda3bb5374 + 4 = 0x7ffda3bb5378
Eu testei o seu código no meu sistema (copiado e colado daqui) e tive os resultados esperados originalmente: ``` blau@xeon:[~/git/cblc/aulas/04-variaveis] (main) $ gcc var5.c blau@xeon:[~/git/cblc/aulas/04-variaveis] (main) $ ./a.out Endereco de a : 0x7ffda3bb5374 <--A no endereço mais alto... Valor de a : 25 Endereco em (p - 1) : 0x7ffda3bb536c Valor em *(p - 1) : 32662 Endereco de b : 0x7ffda3bb5370 <-- B no endereço mais baixo... Valor de b : 17 Endereco em p : 0x7ffda3bb5370 Valor em *p : 17 0x7ffda3bb5374 + 4 = 0x7ffda3bb5378 ```
Owner

@alvaro , eu fui verificar o que pode estar acontecendo e notei que esse resultado específico pode estar relacionado com o gcc. Veja, meu código compilado no Debian com o gcc 14.2 resulta nesse trecho de assembly:

         sub     rsp, 16
         mov     DWORD PTR -12[rbp], 25 ; Carga da variável A na pilha
         mov     DWORD PTR -16[rbp], 17 ; Carga da variável B na pilha

Isso foi obtido com:

gcc -S -masm=intel var4.c

Que gera o arquivo em Assembly var4.s.

Se você experimentar e encontrar uma inversão nessas linhas, é possível que o gcc do Ubuntu seja compilado com uma flag recente que nem existe na minha versão no Debian: fstack-var-order.

Você pode conferir se ela está definida com:

gcc -Q --help=common | grep fstack

Pode ser que ela não apareça, mas se aparecer explica também por que essa inversão acontece no Ubuntu do WSL, como relatado pelo colega Augusto na turma anterior.

@alvaro , eu fui verificar o que pode estar acontecendo e notei que esse resultado específico pode estar relacionado com o gcc. Veja, meu código compilado no Debian com o gcc 14.2 resulta nesse trecho de assembly: ```asm sub rsp, 16 mov DWORD PTR -12[rbp], 25 ; Carga da variável A na pilha mov DWORD PTR -16[rbp], 17 ; Carga da variável B na pilha ``` Isso foi obtido com: ``` gcc -S -masm=intel var4.c ``` Que gera o arquivo em Assembly `var4.s`. Se você experimentar e encontrar uma inversão nessas linhas, é possível que o gcc do Ubuntu seja compilado com uma flag recente que nem existe na minha versão no Debian: `fstack-var-order`. Você pode conferir se ela está definida com: ``` gcc -Q --help=common | grep fstack ``` Pode ser que ela não apareça, mas se aparecer explica também por que essa inversão acontece no Ubuntu do WSL, como relatado pelo colega Augusto na turma anterior.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: blau_araujo/cblc#14
No description provided.