C 语言中的函数指针

Jinku Hu 2023年1月30日 2021年1月22日
  1. 在 C 语言中使用 void (*func)() 符号来定义函数指针
  2. 使用函数指针数组实现类型通用编程特性
C 语言中的函数指针

本文将介绍如何在 C 语言中使用函数指针。

在 C 语言中使用 void (*func)() 符号来定义函数指针

函数指针是 C 语言程序设计中的又一个结构,它实现了动态函数调用、结中包含自己的方法等高级功能,类似于面向对象设计、类型通用程序设计等。需要注意的是,函数指针的声明可能有复杂的语法,即 void(*func)(void) 记号声明了指向 void 函数的指针,该函数不需要参数。虽然在下面的例子中,我们将取单一 int 参数的 printInt 函数的地址分配给 void(*func)(void) 型函数指针。一旦定义了名为 func 的函数指针,就可以用通常的函数调用符号 func(arg) 或用 dereferencing 运算符 (*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);
}

输出:

printed from printInt: 10233
printed from printDouble: 11.234000

另外,我们也可以使用 typedef 为函数指针定义一个新的类型别名,使代码更易读。注意,不同的函数类型需要单独的 typedef 语句。在下面的代码示例中,我们定义了一个没有任何参数的 void 函数指针,尽管如此,printIntprintDouble 函数地址都存储在类型为 FuncPtr 的变量中。需要注意的是,特定函数的地址可以通过显式的&运算符或函数名本身的隐式赋值来获取,这在下一个例子中有所体现。

#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);
}

输出:

printed from printInt: 10233
printed from printDouble: 11.234000

使用函数指针数组实现类型通用编程特性

像其他对象一样,可以用括号 [] 符号定义一个函数指针数组。在运行时可以利用这个数组方便地选择和调用特定的函数。请注意,我们使用的是关键字 _Generic,它是 switch 一样的表达式,让用户根据控制表达式的类型评价来选择具体的情况。因此,我们实现了下面的代码示例,根据 switch 条件中传递的变量类型,调用相应的 print 函数。请注意,enum 类型也被用来定义不同情况下的常量值。

#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);
}

输出:

printed from printInt: 10233
printed from printDouble: 11.234000
Author: 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

相关文章 - C Pointer