quarta-feira, 22 de agosto de 2018

C: Ponteiros para função

Em C existe um recurso muito incomum. Ponteiros para funções. Não sei de outra linguagem que tenha isto, além de C e C++. Não sei se outras linguagens derivadas do C, como Java e C# tem isto (Podem responder nos comentários). Dá para fazer em Assembly, mas isto não conta.

Qual é o uso disto? Depende do caso. É possível passar uma função, aliás, o endereço de uma função, como parâmetro para outra função, para que ela a chame dentro dela, por exemplo.

Então vamos a um exemplo prático:

#include        <stdio.h>

typedef int     (*funcao_t)(int,int);

int soma( int a, int b );
int subr( int a, int b );
int divi( int a, int b );
int mult( int a, int b );


funcao_t        array_f[] =
{
        soma,
        subr,
        divi,
        mult
} ;

int soma( int a, int b )
{
        return a+b ;
}

int subr( int a, int b )
{
        return a-b ;
}

int divi( int a, int b )
{
        return a/b ;
}

int mult( int a, int b )
{
        return a*b ;
}


int main()
{
        int i ;

        for( i = 0 ; i < 4 ; i++ )
                printf( "%d: %d\n",i,array_f[i](12,3) );
}


O tipo funcao_t é criado como um tipo de ponteiro para uma função com dois parâmetros inteiros.

São feitos os protótipos de 4 funções, cada uma referente a uma das 4 operações aritméticas básicas. A função retorna a referida operação entre os parâmetros.

Um array, o array_f, de ponteiros para funções é criado, e inicializado com cada uma das funções. É só o nome da função, sem os parênteses.

Note que o tamanho deste array não é informado, então o compilador obtém da quantidade de dados da inicialização.

Depois coloquei o código das funções das operações básicas.

E finalmente a função main(). Nela o array array é varrido chamando cada função apontada nos elementos do array de funções, passando dois parâmetros, e a resposta vai para saída padrão.

A saída é:

0: 15
1: 9
2: 4
3: 36


Isto pode parecer um recurso inútil para uma linguagem de programação, mas tem contextos específicos nos quais pode ser muito útil. Um deles é fazer algumas coisas típicas de orientação a objetos em C, que não é orientado a objetos.

Aviso

O uso de um ponteiro de função não adequadamente inicializado, que não aponte realmente para uma função, é catastrófico. Quase certamente o programa abortará ao chamar o que é apontado por ele.

Compatibilidade

Poucas vezes usei isto, mas não vi um compilador sequer não aceitar isto. A primeira vez que usei foi em 1987, em um PDP 11/70, com um compilador C K&R. Portanto, se o seu copilador não aceitar isto, pode jogar ele fora.

Este programa exemplo foi testado em um Solaris 5.11 com um compilador GCC e em um FreeBSD 12.0 com um compilador clang version 5.0.0.

Nenhum comentário:

Postar um comentário