Ainda aprendo coisas com C…

Olhe só que interessante: Você sabia que é possível usar um ponteiro para saltar para qualquer lugar do seu programa? Veja só um exemplo:

#include <stdio.h>

__attribute__((noreturn)) void f(void)
{ puts("Eu sou f()."); exit(0); }

int main(int argc, char *argv[])
{
  void *ptr = f;
  goto *ptr;
}

Marquei a função f() com o atributo “noreturn” porque não precisamos de retorno (de fato, se houver um, você tomará um SIGSEGV na cara!).

Isso não parece lá muito útil, não é? Mas e se pudessemos obter o endereço de labels dentro de uma função? Olhem isso:

#include <stdio.h>

int main(int argc, char *argv[])
{
  void *ptr = &&f;
  goto *ptr;
  puts("Código jamais executado!");

f:
  puts("Hello!");
}

O uso do operador && como “endereço-de” para labels é uma extensão do GCC.

O compilador otimizará o código acima, mas ele é útil para demonstrar que é possível criar uma tabela contendo endereços, dentro da mesma função, e com alguma lógica, decidir para onde saltar. De fato, a função vfprintf(), internamente, faz isso (e foi lá que vi o macete!):

void myfunc(int x)
{
  static void *jmptable[3] = { &&do_1, &&do_2, &&do_3 };

  if (x < 0 || x > 2)
    goto dont_do;
  goto *jmptable[x];

dont_do:
  puts("x precisa estar entre 0 e 2.");
  goto end;

do_1:
  puts("zero!");
  goto end;

do_2:
  puts("um!");
  goto end;

do_3:
  puts("dois!");

end: ;
}

OBS: Só declarei ‘jmptable’ como static para que a tabela seja inicializada apenas uma vez entre as chamadas de ‘myfunc’.

Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s