O objetivo deste trabalho é implementar em C uma função
gera_func
que recebe como parâmetros uma função f
e a descrição de seus parâmetros e retorna uma "nova versão" de
f
, gerada dinamicamente que, ao ser chamada,
só precisa receber os valores dos parâmetros que não foram "amarrados" (fixados) por
gera_func
.
Como exemplo, considere a função pow
, da biblioteca matemática,
que retorna o valor de seu primeiro parâmetro (x) elevado ao segundo (y):
double pow (double x, double y);A função
gera_func
nos permite criar dinamicamente uma nova função
que sempre eleva o seu parâmetro ao quadrado.
Para criar essa função, gera_func
amarra
o segundo parâmetro de pow
,
construindo, em tempo de execução, o código de uma função que chama pow
com dois parâmetros: o primeiro é seu próprio parâmetro e o segundo é
o valor 2.0. Quando pow
retornar, essa função retorna
o valor retornado por pow
.
Também deve ser implementada uma função libera_func
,
que é responsável por liberar a função criada dinamicamente por gera_func
.
Leia com atenção o enunciado do trabalho e as instruções de entrega.
Em caso de dúvidas, não invente. Pergunte!
A função gera_func
deve ter o seguinte protótipo:
void* gera_func (void* f, int n, Parametro params[]);onde
f
tem o endereço da função a ser chamada,
o array params
contém a lista de parâmetros
de f
e n
é o número de parâmetros descritos
por params
.
O tipo Parametro
é definido como:
typedef enum {INT_PAR, CHAR_PAR, DOUBLE_PAR, PTR_PAR} TipoParam; typedef struct { TipoParam tipo; /* indica o tipo do parâmetro */ int amarrado; /* indica se o parâmetro deve ter um valor amarrado */ union { int v_int; char v_char; double v_double; void* v_ptr; } valor; /* define o valor do parâmetro se este for amarrado */ } Parametro;
A função libera_func
deve ter o protótipo a seguir:
void libera_func (void* func);
O arquivo gera_func.h
contém as definições acima, e
pode ser pego AQUI. O trabalho deve seguir
estritamente as definições constantes nesse arquivo.
gera_func
para criar dinamicamente uma função que
eleva números ao quadrado e depois invoca essa função para obter
os quadrados de 1 a 10:
#include <math.h> #include <stdio.h> #include "gera_func.h" typedef double (*func_ptr) (double); int main (void) { Parametro params[2]; func_ptr f_quadrado = NULL; double d; int i; params[0].tipo = DOUBLE_PAR; params[0].amarrado = 0; params[1].tipo = DOUBLE_PAR; params[1].amarrado = 1; params[1].valor.v_double = 2.0; f_quadrado = (func_ptr) gera_func (pow, 2, params); for (i = 1; i <= 10; i++) { d = f_quadrado(i); printf("%d ^ 2 = %f\n", i, d); } libera_func(f_quadrado); return 0; }Um outro exemplo é uma implementação genérica de BubbleSort que recebe como argumentos o array a ser ordenado e uma função para a comparação de dois elementos. O arquivo gensort.c mostra um exemplo dessa implementação genérica e de funções que poderiam ser usadas como seu segundo argumento. A função
gera_func
poderia ser usada para gerar duas versões dessa
implementação, para ordenações em ordem crescente e em ordem decrescente.
Essas duas versões podem ser criadas "amarrando-se" a função de comparação.
A função gera_func
deve ser implementada em C,
mas ela deve gerar, em um bloco de memória alocado, um trecho de código em
linguagem de máquina que implementa a função criada dinamicamente.
O valor de retorno de gera_func
será um ponteiro para esse bloco de
memória.
De forma geral, gera_func
irá percorrer o array com a descrição
dos parâmetros e gerar um código em linguagem de máquina que:
push
para empilhar os parâmetros
para a função original, respeitando os tipos e eventuais valores amarrados
especificados no array params
;
call
;
minhamaquina> gcc -m32 -c code.sA opção -c é usada para compilar e não gerar o executável. Depois de compilar, veja o código de máquina gerado usando:
minhamaquina> objdump -d code.oA seguir, por exemplo, implemente e teste a geração de código para chamar uma função que retorna o valor de seu parâmetro inteiro, sem fixar e depois fixando o valor desse parâmetro. Vá depois aumentando o número e os tipos de parâmetros tratados. Use os exemplos dados no enunciado do trabalho mas faça também testes mais completos!
Será descontado um ponto
por cada dia de atraso (incluindo sábado, domingo e feriados).
Leia com atenção as intruções para entrega a seguir:
gera_func
e libera_func
. Esse arquivo não deve conter a
função main
.
/* Nome_do_Aluno1 Matricula Turma */ /* Nome_do_Aluno2 Matricula Turma */Coloque também no relatorio o nome dos integrantes do grupo
objdump
será provavelmente a maior fonte de referência.
Os opcodes das instruções em linguagem de máquina que devem ser
geradas dinamicamente também podem ser obtidos
no Intel Pentium Instruction Set Reference Manual (Volume 2).