Básico de ponteiros com o GDB

September 21, 2009

[Warning: This post is a backup recovery from my previous Wordpress blog. All content was automatically converted accessing a MySQL database using a Python script (details). Mostly are in Portuguese but if you are interest I can translate to English. If you found any problem dont’t hesitate to contact me in comments.]

Esse é um pequeno lembrete para quem quer pegar o conceito de ponteiro rápido. É tão simples que nem programa direito você vai precisar, só seguir sua intuição e o GDB ;-)

1. Básico

Vamos começar com um código muito simples.

#include 
int main(int argc, char *argv[]) {
int *ptr = NULL;
int variavel_A;
int variavel_B;
variavel_A = 5;
variavel_B = 18;
return 0;
}
</pre>

Usar o menor comando do GCC para compilar e linkar o programa. A saída (o executável) chamará a.out, se você quiser outro nome adicione "-o <nome>" no final do comando.

gcc -ggdb basico.c

E iniciar o depurador, lembre-se que o texto em (vermelho) é comentário e negrito é um comando para você digiar na CLI (command-line interface) do GDB.

maluta@coding ~ $ gdb -q a.out (gdb) l (lista o código) 1 #include <stdio.h> 2 3 4 int main(int argc, char *argv[]) { 5 6 int *ptr = NULL; 7 int variavel_A; 8 int variavel_B; 9 10 variavel_A = 5; (gdb) 11 variavel_B = 18; 12 13 return 0; 14 15 } (gdb) break 13 (inserir um breakpoint na linha 13) Breakpoint 1 at 0x80483c6: file basico.c, line 13. (gdb) r (run - inicia o programa) Starting program: /home/maluta/a.out Breakpoint 1, main () at basico.c:13 13 return 0; (Mostra o que tem na variavel_A) (gdb) print variavel_A $1 = 5
(Mostra o que tem na variavel_B) (gdb) print variavel_B $2 = 18 (Imprime o conteúdo do endereço definido em ptr) (gdb) print *ptr Cannot access memory at address 0x0 (ooops... essa não é uma posição válida!) (gdb) print ptr (mas é claro que ptr guarda um valor...) $3 = (int *) 0x0 (que é NULL)
(E qual o endereço da variável_A?) (gdb) print &variavel_A $4 = (int *) 0xbfbc0ddc (gdb) print *variavel_A (Podemos ver que não conseguimos acessar a variavel_A como um ponteiro pois ela guarda um endereço inválido) Cannot access memory at address 0x5
(O endereço da variável_B) (gdb) print &variavel_B $5 = (int *) 0xbfbc0de0 (Vamos fazer ptr apontar para a variavel_A) (gdb) set ptr=0xbfbc0ddc (gdb) print *ptr (e mostrar o seu conteúdo) $6 = 5 (Vamos fazer ptr apontar para a variavel_B) (gdb) set ptr=&variavel_B (gdb) print *ptr $7 = 18 (gdb)
2. Intermediário Vamos dar mais um passo.
#include 
#include  /* malloc() */
#include  /* strncpy */
int main(int argc, char *argv[]) {

        char *nome;

        nome = malloc(10*sizeof(char));
        strncpy(nome,"tiago",5);
        return 0;
}
maluta@coding ~ $ gdb -q a.out (gdb) l 1 #include <stdio.h> 2 #include <stdlib.h> /* malloc() */ 3 #include <string.h> /* strncpy */ 4 int main(int argc, char *argv[]) { 5 6 7 char *nome; 8 9 nome = malloc(10*sizeof(char)); 10 (gdb) break 9 Breakpoint 1 at 0x8048421: file intermediario.c, line 9. (gdb) r Starting program: /home/maluta/a.out Breakpoint 1, main () at basico.c:9 9 nome = malloc(10*sizeof(char)); (gdb) print nome $1 = 0xb80b1190 "U\211åWVSèÀ\207" (LIXO) (gdb) n (next - executa a próxima instrução) 11 strncpy(nome,"tiago",5); (gdb) n 15 return 0; (gdb) print nome (texto copiado) $2 = 0x804b008 "tiago" (gdb) x/5x nome (conteudo em hexa) 0x804b008: 0x74 0x69 0x61 0x67 0x6f (gdb) x/5c nome (conteudo em ascii) 0x804b008: 116 't' 105 'i' 97 'a' 103 'g' 111 'o' (Vamos mudar a primeira letra da string) (gdb) set {char}nome='T' (gdb) x/5x nome 0x804b008: 0x54 0x69 0x61 0x67 0x6f (gdb) x/5c nome 0x804b008: 84 'T' 105 'i' 97 'a' 103 'g' 111 'o' (Vamos colocar um espaço em branco na segunda posição) (gdb) set {char}(nome+1)=' ' (lembre-se que o índice começa em zero) (gdb) print nome $11 = 0x804b008 "T ago" (gdb) x/5x nome 0x804b008: 0x54 0x20 0x61 0x67 0x6f (gdb) x/5c nome 0x804b008: 84 'T' 32 ' ' 97 'a' 103 'g' 111 'o' (Você pode ver o conteúdo da variável com deslocamento 'offset') (gdb) print nome+3 $17 = 0x804b00b "go"

Meu amigo Antônio (aka John) fez um exemplo do uso de classes em C, vamos utilizá-lo por aqui. Para mostrar o ponteiro para função, só vou adicionar uma função/método subtraiMinhaClasse no código.

#include 

struct MinhaClasse{
    int a;
    int b;
    int (*soma)();
};

int somaMinhaClasse(struct MinhaClasse *this){
    return (*this).a + (*this).b;
}

int subtraiMinhaClasse(struct MinhaClasse *this){
    return (*this).a - (*this).b;
}

void construtorMinhaClasse(struct MinhaClasse *this){
    this->soma = somaMinhaClasse;
}

int main(){

    int resposta;
    struct MinhaClasse objeto;
    construtorMinhaClasse(&objeto);

    objeto.a = 33;
    objeto.b = 15;

    resposta = objeto.soma();

    printf("%i",resposta);

return 0;
}
(gdb) break 34 Breakpoint 1 at 0x8048425: file john.c, line 34. (gdb) r Starting program: /home/maluta/a.out Breakpoint 1, main () at john.c:34 29 printf("%i",resposta);
(Vamos ver o que tem na struct) (gdb) print objeto $1 = {a = 33, b = 15, soma = 0x80483d0 <somaMinhaClasse>}
(Bem como o valor contido em resposta) (gdb) print resposta $2 = 48
(Qual o endereço da função somaMinhaClasse?) (gdb) print somaMinhaClasse $3 = {int (struct MinhaClasse *)} 0x80483d0 <somaMinhaClasse>
(Que interessante... objeto.soma e somaMinhaClasse tem o mesmo endereço?) (gdb) print objeto.soma $4 = (int (*)()) 0x80483d0 <somaMinhaClasse>
(E a função subtraiMinha classe está sozinha?) (gdb) print subtraiMinhaClasse $5 = {int (struct MinhaClasse *)} 0x80483e3 <subtraiMinhaClasse>
(Que tal conectá-la a alguém?) (gdb) set objeto.soma=subtraiMinhaClasse (E lógico ver o resultado!) (gdb) print objeto.soma() $6 = 18 (O novo par de objeto.soma ;-)) (gdb) print objeto.soma $8 = (int (*)()) 0x80483e3 <subtraiMinhaClasse>
(Não gostei! Quero voltar para o que tinha antes) (gdb) set objeto.soma=somaMinhaClasse (gdb) print objeto.soma() $9 = 48