好久不使用C语言写底层代码,最近学习OS又要捡起这个古老而神奇的工具了。

这里温习一下C语言的函数指针的用法

例子引自Basics of Function Pointers in C

函数指针的一般用法

#include <stdio.h>

//函数原型
void sayHello();

//函数实现
void sayHello(){
    printf('hello world');
}

int main(){
    //普通调用
    sayHello();
    //函数指针调用
    void (*sayHelloPtr)() = sayHello;
    //或: void (*sayHelloPtr)() = &sayHello;
    
    (*sayHelloPtr)();
    //或: sayHelloPrt();
}

注意函数指针调用部分

void (*sayHelloPtr)() 这部分比较难以理解,有以下几点分析

void (*sayHelloPtr)() = sayHellosayHello这个函数名赋给了新建的函数指针。函数名代表函数的地址,并且可以赋值给函数指针。这与语句int *x = &myint;中把myint的地址赋给一个指向整数的指针一样。只是当考虑函数的时候,不需要加上取地址符&(似乎加上也可以)。简而言之,函数名就是它的地址。接着用代码(*sayHelloPtr)();解引用并调用了函数指针。

将函数指针作为参数传递

#include <stdio.h>
 
// 函数原型
int add(int x, int y);
int subtract(int x, int y);
int domath(int (*mathop)(int, int), int x, int y);
 
// 加法 x + y
int add(int x, init y) {
    return x + y;
}
 
// 减法 x - y
int subtract(int x, int y) {
    return x - y;
}
 
// 根据输入执行函数指针
int domath(int (*mathop)(int, int), int x, int y) {
    return (*mathop)(x, y);
}
 
// main函数调用
int main() {
 
    // 用加法调用domath
    int a = domath(add, 10, 2);
    printf("Add gives: %d\n", a);
    
    // 用减法调用domath
    int b = domath(subtract, 10, 2);
    printf("Subtract gives: %d\n", b);
}

函数名和地址

#include <stdio.h>
 
// 函数原型
void add(char *name, int x, int y);
 
// 加法 x + y
void add(char *name, int x, int y) {
    printf("%s gives: %d\n", name, x + y);
}
 
// main函数调用
int main() {
 
    // 一些糟糕的函数指针赋值
    void (*add1Ptr)(char*, int, int) = add;
    void (*add2Ptr)(char*, int, int) = *add;
    void (*add3Ptr)(char*, int, int) = &add;
    void (*add4Ptr)(char*, int, int) = **add;
    void (*add5Ptr)(char*, int, int) = ***add;
 
    // 仍然能够正常运行
    (*add1Ptr)("add1Ptr", 10, 2);
    (*add2Ptr)("add2Ptr", 10, 2);
    (*add3Ptr)("add3Ptr", 10, 2);
    (*add4Ptr)("add4Ptr", 10, 2);
    (*add5Ptr)("add5Ptr", 10, 2);
 
    // 当然,这也能运行
    add1Ptr("add1PtrFunc", 10, 2);
    add2Ptr("add2PtrFunc", 10, 2);
    add3Ptr("add3PtrFunc", 10, 2);
    add4Ptr("add4PtrFunc", 10, 2);
    add5Ptr("add5PtrFunc", 10, 2);
}

运行这段代码,会看到每个函数指针都会执行,只是会收到一些关于字符转换的警告。但是,这些函数指针都能正常工作。

显然,这段代码不是优秀的实例代码。我们从中收获到了如下知识:

小结

函数指针是C语言中的强大工具,基于函数指针,可以实现回调和基本的面向对象功能,后者也是本次回顾函数指针的原因。

Reference