Ponteiro de funções em C

Jinku Hu 12 outubro 2023
  1. Utilize void (*func)() Notação para definir ponteiro de função em C
  2. Utilizar a Function Pointer Array para implementar a função de programação genérica do tipo
Ponteiro de funções em C

Este artigo irá introduzir como utilizar um ponteiro de função em C.

Utilize void (*func)() Notação para definir ponteiro de função em C

Os apontadores de funções são mais uma construção na programação em C que implementam características avançadas como a chamada dinâmica de funções, estruturas que incluem os seus próprios métodos semelhantes ao design orientado para objectos, programação genérica de tipo e etc. Note-se que a declaração do ponteiro de função pode ter uma sintaxe complicada, nomeadamente, void (*func)(void) notação declara o ponteiro para a função void que não toma parâmetros. Embora atribuamos o endereço da função printInt, isso leva um único argumento int à função void (*func)(void) tipo ponteiro de função no exemplo seguinte. Uma vez definido o ponteiro de função chamado func, pode ser chamado com a notação habitual de chamada de função func(arg) ou com o operador de desreferenciação (*func)(arg).

#include <stdio.h>
#include <stdlib.h>

void printInt(int x) { printf("printed from printInt: %d\n", x); }

int main() {
  int input1 = 10233;

  void (*func)(int) = printInt;

  func(input1);
  (*func)(input1);

  exit(EXIT_SUCCESS);
}

Resultado:

printed from printInt: 10233
printed from printDouble: 11.234000

Em alternativa, podemos definir um novo tipo de pseudónimo de um ponteiro de função utilizando typedef para tornar o código mais legível. Note-se que tipos diferentes de funções precisariam de declarações separadas de typedef. Na seguinte amostra de código, definimos um ponteiro para uma função vazia sem quaisquer argumentos; no entanto, tanto os endereços das funções printInt como printDouble são armazenados na variável do tipo FuncPtr. É de notar que o endereço da função específica pode ser tomado com operador explícito & ou com a atribuição implícita do próprio nome da função, como demonstrado no exemplo seguinte.

#include <stdio.h>
#include <stdlib.h>

typedef void (*FuncPtr)();

void printInt(int x) { printf("printed from printInt: %d\n", x); }

void printDouble(double x) { printf("printed from printDouble: %f\n", x); }

int main() {
  int input1 = 10233;
  double input2 = 11.234;

  FuncPtr func1 = printInt;
  FuncPtr func2 = printDouble;

  func1(input1);
  func2(input2);

  exit(EXIT_SUCCESS);
}

Resultado:

printed from printInt: 10233
printed from printDouble: 11.234000

Utilizar a Function Pointer Array para implementar a função de programação genérica do tipo

Como outros objectos, pode-se definir um array de apontadores de funções com parênteses []notação. Esta matriz pode ser utilizada para escolher e chamar facilmente funções específicas durante o tempo de execução. Note-se que estamos a utilizar a palavra-chave _Generic, que é switch, como uma expressão que permite ao utilizador escolher o caso específico com base na avaliação do tipo da expressão de controlo. Consequentemente, implementamos o seguinte exemplo de código, onde a função print correspondente é chamada com base no tipo da variável passada na condição switch. Note-se que, o tipo enum também é utilizado para definir valores constantes para diferentes casos.

#include <stdio.h>
#include <stdlib.h>

enum TYPE { INTEGER, DOUBLE, INVALID };

#define typename(x) \
  _Generic((x), int: INTEGER, double: DOUBLE, default: INVALID)

typedef void (*FuncPtr)();

void printInt(int x) { printf("printed from printInt: %d\n", x); }

void printDouble(double x) { printf("printed from printDouble: %f\n", x); }

int main() {
  int input1 = 10233;
  double input2 = 11.234;

  FuncPtr func_ptrs[] = {printInt, printDouble};

  switch (typename(input1)) {
    case INTEGER:
      func_ptrs[INTEGER](input1);
      break;
    case DOUBLE:
      func_ptrs[DOUBLE](input1);
      break;
    case INVALID:
      printf("No corresponding type found!\n");
    default:
      break;
  }

  switch (typename(input2)) {
    case INTEGER:
      func_ptrs[INTEGER](input2);
      break;
    case DOUBLE:
      func_ptrs[DOUBLE](input2);
      break;
    case INVALID:
      printf("No corresponding type found!\n");
    default:
      break;
  }

  exit(EXIT_SUCCESS);
}

Resultado:

printed from printInt: 10233
printed from printDouble: 11.234000
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Artigo relacionado - C Pointer