ELT048 - SOE



  Ponteiros de função

       Rodrigo Almeida
Universidade Federal de Itajubá
Revisão
●   Ponteiros
●   Struct
●   Buffer circular
●   Ponteiro para void
Exercício
●   Implementar um buffer circular
●   Utilizar um vetor de 10 posições
●   Cada elemento do vetor é uma estrutura com
    duas variáveis
    ●   char tipo
    ●   void* ptr
●   Criar uma função para adicionar novos elementos
    e uma para retirar os mais antigos.
    ●   Add(char tipo, void* var);
    ●   Remove(void);
Exercício
//definição da estrutura
typedef struct {
    char tipo;
    void* ptr;
}process;

//definição do buffer circular
#define BUFFERSIZE 10
process buffer[BUFFERSIZE];

//definição dos “ponteiros” de acesso
int ini, fim;
Exercício
//função de adição de “process” no buffer
void addProc(char ntipo, void* val){

    //checagem de espaço disponível
    if ( ((ini+1)%BUFFERSIZE) < fim){
      //Atualização da posição atual
      buffer[i].tipo = ntipo;
      buffer[i].ptr = val;
      //incremento da posição
      ini = (ini+1)%(BUFFERSIZE);
    }

}
Exercício
//função de remoção de um “process” do buffer
void removeProc (void){

    //checagem se existe alguem pra retirar
    if ( ((fim+1)%BUFFERSIZE) <= ini){
      //incremento da posição
      fim = (fim+1)%(BUFFERSIZE);
    }

}
Exercício
#include “stdio.h”
void main (void){
  int a=5;
  addProc('i', 5);
  addProc('i', a);
  addProc('e', &a);
  removeProc();
  removeProc();
  removeProc();
}
Problema
●   Como executar uma função que não é
    conhecida em tempo de compilação?
    ●   Conhecer o endereço da função em tempo de
        execução.
    ●   Empilhar corretamente os parâmetros que a
        função necessita
    ●   Realizar uma chamada de função para esse
        endereço
●   Onde isso é importante?
Solução
●   Criar rotinas em assembly que recebem o
    endereço da função, empilham todas as
    variáveis corretas e façam uma chamada
    de função para o endereço (JSR)


    ou

●   Utilizar ponteiros de função em C
Ponteiros de Função
●   Armazenam o endereço do início de uma função.
●   A manipulação do valor obedece todas as regras
    de manipulação de ponteiros.
    ●   A única exceção é na chamada da função
        apontada.
●   Apresenta uma declaração complexa.
●   É necessário indicar a assinatura da função: a
    quantidade e tipos dos parâmetros.
    ●   É comum utilizar um typedef para simplificar a
        criação dos ponteiros.
Definição de ponteiros de função
//definindo um tipo de ponteiro de função que
//   não recebe nenhum parâmetro
//   não retorna nenhum valor
typedef void (*pointerTest)(void);
//definição do ponteiro foo via typedef
pointerTest foo;

//definição do ponteiro bar sem typedef
void (*bar)(void);
Definição de ponteiros de função
//funções
void func1 (void){
  printf("Primeira Função")
}
void func2 (void){
  printf("Segunda Função")
}
//criando um ponteiro para função
pointerTest foo;

foo = func1; //Nota: Sem parênteses
(*foo)(); //chamando a função 1

foo = func2; //Nota: Sem parênteses
(*foo)(); //chamando a função 2
Engine de processamento
●   O principal uso de um ponteiro de função é
    permitir que o programa rode uma função
    arbitrária não conhecida em tempo de
    compilação com uma menor complexidade.
         ●   menor complexidade = sem apelar para asm.
●   Isto permite ao programador desenvolver
    “engines” de processamento.
●   As “engines” realizam uma série de
    preparações/checagens/testes antes de
    executar as funções.
Engine de processamento
●   Objetivo:
    ●   Fazer uma engine
        de um processador
        gráfico
    ●   Utilização de um
        switch com
        passagem de
        parâmetro para a
        seleção da
        funcionalidade
Engine de processamento
image Blur(image nImg){}
image Sharpen(image nImg){}

image imgEngine(image nImg, int opt){
  image temp;
  //checagem de consistência da imagem
  switch(opt){
    case 1:
      temp = Sharpen(nImg);
      break;
    case 2:
      temp = Blur(nImg);
      break;
  }
  return temp;
}
Engine de processamento
●   Utilização de
    ponteiros de função
    para seleção da
    função
●   Criação de um tipo
    via typedef para
    simplificar o código
Engine de processamento
image Blur(image nImg){}

image Sharpen(image nImg){}

typedef image (*ptrFunc)(image nImg);

//image editor engine
image imgEngine(ptrFunc function, image nImg){
   image temp;
   //checagem de consistência da imagem
   temp = (*function)(nImg);
   return temp;
}
Engine de processamento
●   Vantagens               ●   Desvantagens
    ●   Novas funções não       ●   Ponteiros de função
        alteram a engine            são mais complexos
    ●   O teste do código           para se trabalhar
        da engine só                (pelo menos no
        precisa ser feito           começo)
        uma vez                 ●   Nem todos os
    ●   Pode mudar as               compiladores para
        opções                      embarcados
        dinâmicamente               funcionam bem com
                                    ponteiros de função
                                    (Harvard x Von
                                    Neuman)
Exercicio
●   Modifique a estrutura apresentada
    anteriormente para incluir também um
    ponteiro de função.
●   Crie uma função que executa o ponteiro de
    função armazenado na “primeira” posição
    do buffer circular.
●   Crie um main que adicione 3 elementos no
    buffer e execute cada um deles na ordem
    que foram inseridos.
    ●   Add(x3), exec, remove, exec, remove, exec, remove
//código antigo
typedef struct {
    char* NomeDoProcesso;
    int Prioridade;
}process;
#define BUFFERSIZE 10
process buffer1[BUFFERSIZE];
int ini, fim;
void addProc (char *nome, int prio){
  if ( ((ini+1)%BUFFERSIZE) < fim){
    buffer[i].Prioridade = prio;
    buffer[i].NomeDoProcesso = nome;
    ini = (ini+1)%(BUFFERSIZE);
  }
}
void removeProc (void){
  if ( ((fim+1)%BUFFERSIZE) <= ini){
    fim = (fim+1)%(BUFFERSIZE);
  }
}

Ponteiros de Função

  • 1.
    ELT048 - SOE Ponteiros de função Rodrigo Almeida Universidade Federal de Itajubá
  • 2.
    Revisão ● Ponteiros ● Struct ● Buffer circular ● Ponteiro para void
  • 3.
    Exercício ● Implementar um buffer circular ● Utilizar um vetor de 10 posições ● Cada elemento do vetor é uma estrutura com duas variáveis ● char tipo ● void* ptr ● Criar uma função para adicionar novos elementos e uma para retirar os mais antigos. ● Add(char tipo, void* var); ● Remove(void);
  • 4.
    Exercício //definição da estrutura typedefstruct { char tipo; void* ptr; }process; //definição do buffer circular #define BUFFERSIZE 10 process buffer[BUFFERSIZE]; //definição dos “ponteiros” de acesso int ini, fim;
  • 5.
    Exercício //função de adiçãode “process” no buffer void addProc(char ntipo, void* val){ //checagem de espaço disponível if ( ((ini+1)%BUFFERSIZE) < fim){ //Atualização da posição atual buffer[i].tipo = ntipo; buffer[i].ptr = val; //incremento da posição ini = (ini+1)%(BUFFERSIZE); } }
  • 6.
    Exercício //função de remoçãode um “process” do buffer void removeProc (void){ //checagem se existe alguem pra retirar if ( ((fim+1)%BUFFERSIZE) <= ini){ //incremento da posição fim = (fim+1)%(BUFFERSIZE); } }
  • 7.
    Exercício #include “stdio.h” void main(void){ int a=5; addProc('i', 5); addProc('i', a); addProc('e', &a); removeProc(); removeProc(); removeProc(); }
  • 8.
    Problema ● Como executar uma função que não é conhecida em tempo de compilação? ● Conhecer o endereço da função em tempo de execução. ● Empilhar corretamente os parâmetros que a função necessita ● Realizar uma chamada de função para esse endereço ● Onde isso é importante?
  • 9.
    Solução ● Criar rotinas em assembly que recebem o endereço da função, empilham todas as variáveis corretas e façam uma chamada de função para o endereço (JSR) ou ● Utilizar ponteiros de função em C
  • 10.
    Ponteiros de Função ● Armazenam o endereço do início de uma função. ● A manipulação do valor obedece todas as regras de manipulação de ponteiros. ● A única exceção é na chamada da função apontada. ● Apresenta uma declaração complexa. ● É necessário indicar a assinatura da função: a quantidade e tipos dos parâmetros. ● É comum utilizar um typedef para simplificar a criação dos ponteiros.
  • 11.
    Definição de ponteirosde função //definindo um tipo de ponteiro de função que // não recebe nenhum parâmetro // não retorna nenhum valor typedef void (*pointerTest)(void); //definição do ponteiro foo via typedef pointerTest foo; //definição do ponteiro bar sem typedef void (*bar)(void);
  • 12.
    Definição de ponteirosde função //funções void func1 (void){ printf("Primeira Função") } void func2 (void){ printf("Segunda Função") } //criando um ponteiro para função pointerTest foo; foo = func1; //Nota: Sem parênteses (*foo)(); //chamando a função 1 foo = func2; //Nota: Sem parênteses (*foo)(); //chamando a função 2
  • 13.
    Engine de processamento ● O principal uso de um ponteiro de função é permitir que o programa rode uma função arbitrária não conhecida em tempo de compilação com uma menor complexidade. ● menor complexidade = sem apelar para asm. ● Isto permite ao programador desenvolver “engines” de processamento. ● As “engines” realizam uma série de preparações/checagens/testes antes de executar as funções.
  • 14.
    Engine de processamento ● Objetivo: ● Fazer uma engine de um processador gráfico ● Utilização de um switch com passagem de parâmetro para a seleção da funcionalidade
  • 15.
    Engine de processamento imageBlur(image nImg){} image Sharpen(image nImg){} image imgEngine(image nImg, int opt){ image temp; //checagem de consistência da imagem switch(opt){ case 1: temp = Sharpen(nImg); break; case 2: temp = Blur(nImg); break; } return temp; }
  • 16.
    Engine de processamento ● Utilização de ponteiros de função para seleção da função ● Criação de um tipo via typedef para simplificar o código
  • 17.
    Engine de processamento imageBlur(image nImg){} image Sharpen(image nImg){} typedef image (*ptrFunc)(image nImg); //image editor engine image imgEngine(ptrFunc function, image nImg){ image temp; //checagem de consistência da imagem temp = (*function)(nImg); return temp; }
  • 18.
    Engine de processamento ● Vantagens ● Desvantagens ● Novas funções não ● Ponteiros de função alteram a engine são mais complexos ● O teste do código para se trabalhar da engine só (pelo menos no precisa ser feito começo) uma vez ● Nem todos os ● Pode mudar as compiladores para opções embarcados dinâmicamente funcionam bem com ponteiros de função (Harvard x Von Neuman)
  • 19.
    Exercicio ● Modifique a estrutura apresentada anteriormente para incluir também um ponteiro de função. ● Crie uma função que executa o ponteiro de função armazenado na “primeira” posição do buffer circular. ● Crie um main que adicione 3 elementos no buffer e execute cada um deles na ordem que foram inseridos. ● Add(x3), exec, remove, exec, remove, exec, remove
  • 20.
    //código antigo typedef struct{ char* NomeDoProcesso; int Prioridade; }process; #define BUFFERSIZE 10 process buffer1[BUFFERSIZE]; int ini, fim; void addProc (char *nome, int prio){ if ( ((ini+1)%BUFFERSIZE) < fim){ buffer[i].Prioridade = prio; buffer[i].NomeDoProcesso = nome; ini = (ini+1)%(BUFFERSIZE); } } void removeProc (void){ if ( ((fim+1)%BUFFERSIZE) <= ini){ fim = (fim+1)%(BUFFERSIZE); } }