函数指针(Function Pointer)是存储函数地址的指针变量。通过函数指针可以间接调用函数,实现动态分发。
函数指针的组成:
(*指针名):指针名被括号包围回调函数(Callback Function)是通过函数指针传递给其他函数,在特定时机被调用的函数。
应用场景:
qsort)函数指针数组是存储多个函数指针的数组,常用于实现跳转表(Jump Table)。
Linux内核广泛使用函数指针实现多态,如file_operations结构体将文件操作映射到具体实现。
// 函数指针定义
返回类型 (*指针名)(参数类型1, 参数类型2, ...);
// 使用typedef简化
typedef 返回类型 (*函数指针类型名)(参数类型1, 参数类型2, ...);
函数指针类型名 指针变量;
// 函数指针赋值和调用
指针变量 = 函数名;
指针变量(实参1, 实参2, ...); // 等同于 函数名(实参1, 实参2, ...);
// 函数指针数组
返回类型 (*数组名[大小])(参数列表);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 函数指针基础
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
// 回调函数示例:qsort的比较函数
int compare_int(const void *a, const void *b) {
return (*(int *)a - *(int *)b);
}
int compare_float(const void *a, const void *b) {
float diff = *(float *)a - *(float *)b;
return (diff > 0) ? 1 : (diff < 0) ? -1 : 0;
}
// 回调函数示例:遍历数组并应用函数
void apply_to_array(int arr[], int size, int (*func)(int)) {
for (int i = 0; i < size; i++) {
arr[i] = func(arr[i]);
}
}
int square(int x) { return x * x; }
int negate(int x) { return -x; }
// 函数指针数组(跳转表)
int calculator(int a, int b, int op) {
// 函数指针数组
int (*operations[])(int, int) = {add, subtract, multiply};
if (op >= 0 && op <= 2) {
return operations[op](a, b);
}
return 0;
}
// 模拟内核file_operations
struct file_operations {
int (*open)(const char *path);
int (*read)(int fd, void *buf, int size);
int (*write)(int fd, const void *buf, int size);
int (*close)(int fd);
};
int my_open(const char *path) {
printf("Opening file: %s\n", path);
return 0;
}
int my_read(int fd, void *buf, int size) {
printf("Reading %d bytes from fd %d\n", size, fd);
return size;
}
int my_write(int fd, const void *buf, int size) {
printf("Writing %d bytes to fd %d\n", size, fd);
return size;
}
int my_close(int fd) {
printf("Closing fd %d\n", fd);
return 0;
}
int main() {
// 1. 函数指针基础
printf("=== 函数指针基础 ===\n");
int (*operation)(int, int); // 定义函数指针
operation = add;
printf("add(10, 5) = %d\n", operation(10, 5));
operation = subtract;
printf("subtract(10, 5) = %d\n", operation(10, 5));
operation = multiply;
printf("multiply(10, 5) = %d\n", operation(10, 5));
// 2. qsort使用
printf("\n=== qsort回调 ===\n");
int nums[] = {5, 2, 8, 1, 9, 3};
int n = sizeof(nums) / sizeof(nums[0]);
qsort(nums, n, sizeof(int), compare_int);
printf("Sorted: ");
for (int i = 0; i < n; i++) {
printf("%d ", nums[i]);
}
printf("\n");
// 3. apply_to_array回调
printf("\n=== apply_to_array ===\n");
int arr[] = {1, 2, 3, 4, 5};
int size = 5;
printf("Original: ");
for (int i = 0; i < size; i++) printf("%d ", arr[i]);
printf("\n");
apply_to_array(arr, size, square);
printf("Squared: ");
for (int i = 0; i < size; i++) printf("%d ", arr[i]);
printf("\n");
apply_to_array(arr, size, negate);
printf("Negated: ");
for (int i = 0; i < size; i++) printf("%d ", arr[i]);
printf("\n");
// 4. 函数指针数组(跳转表)
printf("\n=== 跳转表 ===\n");
printf("10 + 5 = %d\n", calculator(10, 5, 0));
printf("10 - 5 = %d\n", calculator(10, 5, 1));
printf("10 * 5 = %d\n", calculator(10, 5, 2));
// 5. 模拟内核操作表
printf("\n=== 内核操作表模式 ===\n");
struct file_operations fops = {
.open = my_open,
.read = my_read,
.write = my_write,
.close = my_close
};
fops.open("/dev/test");
fops.read(0, NULL, 100);
fops.write(0, "data", 4);
fops.close(0);
return 0;
}
编译命令:
gcc -Wall -Wextra -o function_pointer function_pointer.c
./function_pointer
Q1: 函数指针和函数名有什么区别? A: 函数名在表达式中会衰减为函数指针,两者可互换。但函数名是常量,不能赋值;函数指针是变量,可以修改。
Q2: 回调函数有什么优点? A: 解耦调用者和被调用者,实现多态,支持异步编程,便于扩展和测试。
Q3: 如何声明返回函数指针的函数?
A: 使用int (*func(int))(int, int)或typedef简化:typedef int (*fp)(int, int); fp func(int);
Q4: qsort的比较函数为什么用void指针? A: qsort是通用排序函数,不知道元素类型。使用void指针接受任意类型,由比较函数负责类型转换和比较。
Q5: 内核中为什么大量使用函数指针? A: 实现多态和抽象,将接口与实现分离。如VFS层通过函数指针支持不同文件系统,驱动框架支持多种硬件。