1. 函数类型
(1) C语言中的函数有自己特征的类型
(2)函数的类型由返回值,参数类型和参数个数共同决定
int add(int i, int j) 的类型为 int(int, int)
(3) C语言中通过typedef为函数类型重命名
typedef type name(parameter list)
如将 int add(int i, int j) 重命名:
typedef int new_name(int, int);
2. 函数指针
(1) 函数指针用于指向一个函数;
(2)函数名是执行函数体入口的地址;
(3) 可通过函数类型定义函数指针:
FuncType* pointer;
(4)也可以直接定义:
type (*pointer)(parameter list);
- pointer为函数指针变量名
- type 为所指函数的返回值类型
- parameter list 为所指函数的参数类型列表
3. [面试小问题]如何使用C语言直接跳转到某个固定的地址开始执行?
通过函数指针来跳转到某个固定的地址开始执行。具体见以下两个程序。
程序说明:函数指针的使用
#include <stdio.h>
typedef int(FUNC)(int); // 重命名函数名为FUNC,类型为:返回值为int,参数类型为int,参数个数为1个
int test(int i)
{
return i * i;
}
void f()
{
printf("Call f()...\n");
}
int main()
{
FUNC* pt = test; // 定义函数指针pt,并用test初始化(test为函数名,函数名是执行函数体入口的地址)
void(*pf)() = &f; // 定义函数指针pf,并用&f初始化(f为函数名,对一个函数名取地址得到的还是函数体入口的地址,与上一句初始化的含义一样,比较老的编译器是通过这种&f方式对函数指针初始化)【注意与数组名和对数组名取地址的区别】
printf("pf = %p\n", pf);
printf("f = %p\n", f);
printf("&f = %p\n", &f); // 这三个输出结果一样
pf(); // ==> f()
(*pf)(); // ==> f() 这个一般在早期的编译器中出现这种写法
printf("Function pointer call: %d\n", pt(2)); // ==> test(2) ==> 4
return 0;
}
输出结果:
pf = 0x8048459
f = 0x8048459
&f = 0x8048459
Call f() ...
Call f() ...
Function pointer call: 4
总结:
函数名(如f)、对函数名取地址(如&f)都是代表了函数体的入口地址。
程序说明:跳转到固定地址[0x8048459],来执行函数f().
#include <stdio.h>
typedef int(FUNC)(int);
int test(int i)
{
return i * i;
}
void f()
{
printf("Call f() ...\n");
}
int main()
{
FUNC* pt = test;
void(*pf)() = 0x8048459; // 跳转到固定地址
printf("pf = %p\n", pf);
printf("f = %p\n", f);
printf("&f = %p\n", &f);
pf();
(*pf)();
printf("Function pointer call: %d\n", pt(2));
return 0;
}
输出结果:
pf = 0x8048459
f = 0x8048459
&f = 0x8048459
Call f() ...
Call f() ...
Function pointer call:
Function pointer call: 4
4. 回调函数
(1) 回调函数是利用函数指针实现的一种调用机制;
(2)调用机制原理:
- 调用者不知道具体事件发生时需要调用的具体函数;
- 被调用函数不知道何时被调用,只知道需要完成的任务;
- 当具体事件发生时,调用者通过函数指针调用具体函数。
(3)回调函数的有点:回调机制中的调用者和被调函数互不依赖。
(4)应用:设计模式中监听者模式关键技术。
程序说明:回调函数使用示例。
#include <stdio.h>
typedef int(*Weapon)(int);
void fight(Weapon wp, int arg)
{
int result = 0;
printf("Fight boss!\n");
result = wp(arg);
printf("Boss Loss: %d\n", result);
}
int knife(int n)
{
int ret = 0;
int i = 0;
for(i=0; i<n; i++)
{
printf("Knife attack: %d\n", 1);
ret++;
}
return ret;
}
int sword(int n)
{
int ret = 0;
int i = 0;
for(i=0; i<n; i++)
{
printf("Sword attack: %d\n", 5);
ret += 5;
}
return ret;
}
int gun(int n)
{
int ret = 0;
int i = 0;
for(i=0; i<n; i++)
{
printf("Gun attack: %d\n", 10);
ret += 10;
}
return ret;
}
int main()
{
fight(knife, 3);
fight(sword, 4);
fight(gun, 5);
return 0;
}
输出结果:
Fight boss!
Knife attack: 1
Knife attack: 1
Knife attack: 1
Boss Loss: 3
Fight boss!
Sword attack: 5
Sword attack: 5
Sword attack: 5
Sword attack: 5
Boss Loss: 20
Fight boss!
Gun attack: 10
Gun attack: 10
Gun attack: 10
Gun attack: 10
Gun attack: 10
Boss Loss: 50
5. 小结
(1)C语言中的函数都有特定的类型,可以通过typedef重命名函数类型;
(2)可以使用函数类型定义函数指针;
(3) 函数指针是实现回调机制的关键技术;
(4) 通过函数指针可以在C程序中实现固定地址跳转。