O objetivo deste trabalho é implementar uma função create_func
que é capaz de gerar em tempo de execução uma nova função a partir de uma
outra função já existente.
Para isso, create_func
deve receber como parâmetros
uma função f
qualquer (um ponteiro de função em C)
e uma string descrevendo os tipos de seus parâmetros e valor de retorno.
A função create_func
deve então gerar uma nova função
que, quando chamada, recebe como parâmetro um vetor com os parâmetros a serem passados para f
, chama a função f
, e armazena o valor
de retorno de f
no mesmo vetor dos parâmetros.
A função create_func
deve ter o seguinte protótipo:
DynCall create_func (void* f, const char* signature);onde o parâmetro
f
é um ponteiro para uma função já existente e o parâmetro signature
descreve a assinatura de f
(veja aqui como é feita essa descrição). O valor de retorno de create_func
é um ponteiro para a função gerada dinamicamente, e o tipo ponteiro para função DynCall
é definido como:
typedef void (*DynCall) (Any* params); /*ponteiro para funções que recebem um vetor de Any como parâmetro, sem valor de retorno*/e
Any
é definido como:
typedef union { int i; char c; double d; float f; void* p; } Any;As funções geradas por
create_func
recebem como parâmetro um vetor com os parâmetros que devem ser passados para a função f
. A primeira posição desse vetor (índice 0) é sempre reservada para o valor de retorno de f
, mesmo que f
não tenha valor de retorno. Os parâmetros a serem passados para f
começam a partir da segunda posição do vetor, obedecendo a ordem em que eles aparecem na assinatura de f
.
Também deve ser implementada a função
void free_func (DynCall func);que é responsável por liberar uma função criada dinamicamente.
A função create_func
deve ser implementada em C,
mas ela deve gerar, em uma área de memória, um trecho de código em
linguagem de máquina que implementa a função criada dinamicamente.
De forma geral, create_func
irá percorrer a string com a descrição
da assinatura da função original e gerar um código em linguagem de máquina que:
params
, respeitando os
tipos especificados na assinatura da função;
push
para empilhar esses parâmetros
para a função original;
call
;
create_func
serão descritas através de strings, onde os tipos dos parâmetros e do valor de retorno serão indicados por um caractere da seguinte forma:
int
char
double
float
'>'
. Veja a seguir alguns exemplos de codificação de assinatura de funções:
float f (int a, int b);
- "ii>f"
void g (int a, double b);
- "id"
double h (int n, double* v);
- "ip>d"
Considere a função
double pow (double x, double y);definida em
math.h
.
O trecho de programa a seguir cria dinamicamente uma função que recebe os parâmetros para a função pow
através de um array. Essa função é usada para calcular os quadrados de 0 a 10.
#include <math.h> #include <stdio.h> #include "dyncall.h" int main (void) { int i; Any params[3]; DynCall f = create_func(pow,"dd>d"); params[2].d = 2.0; /* todos os numeros serao elevados ao quadrado */ for (i = 0; i <= 10; i++) { params[1].d = i; f(params); printf("%.0f^%.0f = %.0f\n",params[1].d,params[2].d,params[0].d); } free_func(f); return 0; }Nesse exemplo,
create_func
cria em tempo de execução uma nova
função baseada na função pow
.
Essa nova função recebe os parâmetros para pow
nas posições de índice 1 e 2 do vetor params
, e armazena na posição de índice 0 do vetor params
o resultado de pow
. A seguir ilustramos através de um código equivalente em C como deveria ser o código em linguagem de máquina gerado por create_func
nesse caso:
void df (Any* v) { v[0].d = pow(v[1].d, v[2].d); }
dyncall.c
(não inclua nenhuma função main
nesse arquivo).
/* Nome_do_Aluno1 Matricula1 */ /* Nome_do_Aluno2 Matricula2 */
dyncall.h
pode ser pego
AQUI.
O trabalho deve seguir estritamente as definições constantes nesse arquivo.
Trabalhos que não compilem utilizando o arquivo fornecido terão nota zero.