C函数指针的理解与使用
通过一些具体例子,来深入理解并掌握函数指针的运用。
C语言函数指针的理解与使用
函数指针的定义
函数指针就是函数的指针。它是一个指针,指向一个函数。看例子:
1 | A) char* (*fun1)(char* p1, char* p2); |
上面三个表达式分别什么意思?
- 这很容易,fun3是函数名,p1,p2是参数,其类型为
char*
型,函数的返回值为char*
类型。
- 这很容易,fun3是函数名,p1,p2是参数,其类型为
- 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为
char**
,是个二级指针。
- 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为
- fun1是函数名吗?回忆一下数组指针的定义:
1
int (*)[10] p;
这里 fun1 不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。同样,我们把这个表达式改写一下:
1
char* (*)(char* p1, char* p2) fun1;
函数指针使用的例子
1 |
|
赋值方法 给函数指针赋值时,可以用
&fun
或直接用函数名 fun。这是因为函数名被编译之后其实就是一个地址,所以这里两种用法没有本质的差别。如:1
2pf = fun;
pf = &fun;调用方法 可以直接使用指向函数的指针调用函数,无须提前解引用:
1
2
3
4//三个等价调用
pf("aa","bb");
(*pf) ("aa","bb");
fun("aa","bb");
*(int*)&p
是什么
1 | void function(){ |
*(int*)&p = (int)function;
表示什么意思?先看这行代码:
1 | void (*p)(); |
- 这行代码定义了一个指针变量 p,p 指向一个函数,这个函数的参数和返回值都是
void
。 &p
是求指针变量 p 本身的地址,这是一个32位的二进制常数(32位系统)。(int*)&p
表示将地址强制转换成指向 int 类型数据的指针。(int)function
表示将函数的入口地址强制转换成 int 类型的数据。*(int*)&p = (int)function;
表示将函数的入口地址赋值给指针变量 p。- 那么
(*p) ();
就是表示对函数的调用。
64位系统:
1 | void function(){ |
(*(void(*) ())0) ()
是什么
1 | (*(void(*) ())0)(); |
这是《C Traps and Pitfalls》书中的一个例子:
- 第一步:
void(*) ()
,可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。 - 第二步:
(void(*) ())0
,这是将0强制转换为函数指针类型,0是一个地址,也就是说一个函数存在首地址为0的一段区域内。 - 第三步:
(*(void(*) ())0)
,这是取0地址开始的一段内存里面的内容,其内容就是保存在首地址为0的一段区域内的函数。 - 第四步:
(*(void(*) ())0) ()
,这是函数调用。
上面的例子再改写:
1 | (*(char**(*) (char**, char**))0) (char**, char**); |
使用函数指针的好处
可以将实现同一功能的多个模块统一起来标识,这样一来更容易后期的维护,系统结构更加清晰。
归纳为:便于分层设计、利于系统抽象、降低耦合度以及使接口与实现分开。