本文节选自《21天学通C语言》一书
C程序中的函数也都是存放在代码区内的,它们同样也是有地址的。那么如何取得函数的地址呢?在前面也说过函数定义的时候实际上是定义了一个函数变量,那么是否可以将函数变量赋值给其他变量呢?回答这些问题需要涉及另外一个概念:函数型指针。按照已有的指针的知识,顾名思义,函数型指针就是指向函数的指针。如果有一个函数声明为:
int func(const int a, const int b);
那么,此时声明的函数变量add的地址即为这个函数的地址,同时,add的值保存为这个函数的地址,这个特性与数组相似:数组变量与数组变量的地址均为数组的起始地址。而在这个函数声明中,函数类型为int (const int a, const int b)。使用该函数类型来定义一个函数型指针,其方式如下:
int (* fp)(const int a, const int b); /* 其中,参数列表的参数名a和b可省 */
上述语句将变量func定义为指向类型为int (const int a, const int b)的指针操作符和变量名两侧的小括号不可省,否则其含义大不相同。例如:
int * fp(const int a, const int b);
此时,指针操作符与数据类型int结合为int型指针类型,该语句只是声明了一个fp函数,而非定义一个函数指针。为该函数型指针赋值的方式如下:
fp = func;
被赋值的函数变量的类型必须与fp的类型完全一致,包括其返回类型和每一个形参的类型。否则程序将报错。
注意:函数型指针变量赋值时,左值与右值的类型必须完全一致。
使用函数型指针变量调用函数的方法与使用函数变量类似,得到函数地址后再带上参数列表即可。可以使用下面两种方式来调用函数:
fp(5, 6);
或
(*fp)(5, 6);
由于fp被赋值为函数变量func的地址,而func的值又等于其地址,所以*fp可以得到func函数的地址。因此,在调用方式上,可以粗略地将两者视为一致(实际上其后台的处理略有不同)。范例14-7演示了如何使用函数型指针来调用函数。
【范例14-7】使用函数型指针来调用函数,实现方法如示例代码14-7所示。
示例代码14-7
01 #include <stdio.h>
02
03 int add(const int a, const int b) { /* 定义add函数 */
04 return a + b;
05 }
06
07 int main(void) {
08 int (*fp) (const int a, const int b); /* 定义函数指针 */
09
10 fp = add; /* 将其赋值为add */
11 printf("3 + 4 = %d", fp(3, 4)); /* 使用fp计算+ 4的值 */
12 printf("3 + 4 = %d", (*fp)(3, 4)); /* 使用*fp计算+ 4的值 */
13
14 printf("%p", add); /* 输出add的值 */
15 printf("%p", &add); /* 输出add的地址 */
16 printf("%p", fp); /* 输出fp的值 */
17 printf("%p", *fp); /* 输出fp指向的值 */
18
19 return 0;
20 }
【运行结果】程序运行后。
【代码解析】本程序定义了一个函数指针,并将其赋值为相应类型的函数变量add。
第11~12行分别使用fp和*fp的方式调用函数,从图14-12的第1~2行中可以看到它们的调用结果是一样的。
第14~17行输出了add的值和地址、fp的值和指向的值,从图14-12的第3~6行中可以看到它们的调用结果都是一样的。