函数指针(个人参考使用)
2005-12-01 11:14
489 查看
一、函数指针的定义
int (*foo)(); //foo是一个函数指针,它指向一个返回值为int的函数
int *(*foo)(); //foo是一个函数指针,它指向一个返回值为int*的函数
int (*foo[])(); //foo是一个数组,该数组的元素为一个指向返回值为int的函数的指针
int *(*foo[])(); //foo是一个数组,指针指向的类型为一个指向返回值为int×的函数的指针
二、用途
1、回调函数
用户把一个函数指针作为参数传递给其他函数,后者将”回调“用户的函数。任何时候,如果你所编写的函数必须在不同的时刻执行不同类型的工作或执行只能由函数调用者定义的工作,可以使用函数指针。
最常见的是一些窗口系统使用回调函数链接多个动作。
2、转移表
在使用switch语句时,其操作符的代码必须是整数。如果它们是从0开始连续的整数,可以使用转移表来实现和switch相同的任务。
转移表就是一个函数指针数组。
创建一个转移表的步骤主要有两步:
(1)、声明并初始化一个函数指针数组。唯一需要注意的是确保这些函数的原型出现在这个数组声明之前。如:
int foo1(int ,int);
int foo2(int, int);
int foo3(int, int);
....
int (*foo[])(int, int) =
{
foo1, foo2, foo3,....
};
初始化列表中各个函数名的正确顺序取决于程序中用于表示每个操作符的整型代码。
(2)、采用如下语句替换switch语句。
int result = foo[index] (op1, op2);
注意:
在转换表中,越界下标引用就像在其他任何数组中一样是不合法的。一旦出现这种情况,程序可能在三个地方中止:
如果下标值远远越过了数组的边界,它所标识的位置可能在分配给该程序的内存之外。有些操作系统能检测到这个错误并中止程序,但有些操作系统并不这么做。如果程序中止,这个错误将在靠近转换表语句的地方被报告,这时容易诊断。
如果程序并未中止,非法下标所标识的值被提取,处理器跳到该位置,这个不可预测的值可能代表程序中一个有效的地址,但也可能不是这样。如果它不代表一个有效地址,程序此时也会中止,但错误报告的地址从本质上说是一个随机数,此时极难调试。
如果程序此时还未失败,机器将开始执行根据非法下标所获取的虚假地址的指令,此时调试也极为困难。如果这个随即地址位于一块存储数据的内存中,程序通常会很快中止,这通常是由于非法指令或非法的操作数地址所致。要想知道机器为什么会到达那个地方,唯一的线索是转移表调用函数时存储于堆栈中的返回地址。如果任何随机指令在执行时修改了堆栈或堆栈指针,那么连这个线索也没有了。更糟的是,如果这个随机地址恰好位于一个函数的内部,那么该函数会被执行,修改谁也不知道的数据,直到它运行结束。但是函数的返回地址并不是该函数所期望的保存与堆栈上的地址,而是另一个随机值,这个值就成为下一个指令的执行地址,计算机将在各个随机地址间跳转,执行位于那里的指令。
int (*foo)(); //foo是一个函数指针,它指向一个返回值为int的函数
int *(*foo)(); //foo是一个函数指针,它指向一个返回值为int*的函数
int (*foo[])(); //foo是一个数组,该数组的元素为一个指向返回值为int的函数的指针
int *(*foo[])(); //foo是一个数组,指针指向的类型为一个指向返回值为int×的函数的指针
二、用途
1、回调函数
用户把一个函数指针作为参数传递给其他函数,后者将”回调“用户的函数。任何时候,如果你所编写的函数必须在不同的时刻执行不同类型的工作或执行只能由函数调用者定义的工作,可以使用函数指针。
最常见的是一些窗口系统使用回调函数链接多个动作。
2、转移表
在使用switch语句时,其操作符的代码必须是整数。如果它们是从0开始连续的整数,可以使用转移表来实现和switch相同的任务。
转移表就是一个函数指针数组。
创建一个转移表的步骤主要有两步:
(1)、声明并初始化一个函数指针数组。唯一需要注意的是确保这些函数的原型出现在这个数组声明之前。如:
int foo1(int ,int);
int foo2(int, int);
int foo3(int, int);
....
int (*foo[])(int, int) =
{
foo1, foo2, foo3,....
};
初始化列表中各个函数名的正确顺序取决于程序中用于表示每个操作符的整型代码。
(2)、采用如下语句替换switch语句。
int result = foo[index] (op1, op2);
注意:
在转换表中,越界下标引用就像在其他任何数组中一样是不合法的。一旦出现这种情况,程序可能在三个地方中止:
如果下标值远远越过了数组的边界,它所标识的位置可能在分配给该程序的内存之外。有些操作系统能检测到这个错误并中止程序,但有些操作系统并不这么做。如果程序中止,这个错误将在靠近转换表语句的地方被报告,这时容易诊断。
如果程序并未中止,非法下标所标识的值被提取,处理器跳到该位置,这个不可预测的值可能代表程序中一个有效的地址,但也可能不是这样。如果它不代表一个有效地址,程序此时也会中止,但错误报告的地址从本质上说是一个随机数,此时极难调试。
如果程序此时还未失败,机器将开始执行根据非法下标所获取的虚假地址的指令,此时调试也极为困难。如果这个随即地址位于一块存储数据的内存中,程序通常会很快中止,这通常是由于非法指令或非法的操作数地址所致。要想知道机器为什么会到达那个地方,唯一的线索是转移表调用函数时存储于堆栈中的返回地址。如果任何随机指令在执行时修改了堆栈或堆栈指针,那么连这个线索也没有了。更糟的是,如果这个随机地址恰好位于一个函数的内部,那么该函数会被执行,修改谁也不知道的数据,直到它运行结束。但是函数的返回地址并不是该函数所期望的保存与堆栈上的地址,而是另一个随机值,这个值就成为下一个指令的执行地址,计算机将在各个随机地址间跳转,执行位于那里的指令。
相关文章推荐
- 个人C/C++编码规范______仅供个人参考使用
- 【个人笔记重点,不作为参考】主题:Mac OSX下Sublime Text配置使用Ctags实现代码跳转
- 个人使用的.vimrc 供大家参考
- 【个人笔记重点,不作为参考】主题:Angular2中使用ngx-translate进行国际化
- Zend Studio以及开发框架(引擎)使用上的个人总结(无参考价值、个人备忘)
- Centos6.5 XDMCP等图形服务的搭建与使用(大部分参考私房菜)
- 使用阿里云一年多个人经验之谈。(转)
- 个人喜好的缩进风格: indent工具使用[linux]
- 使用花生壳、路由器、个人电脑进行站点部署并实现外网域名访问图文详解(花生壳设置方法 使用方法 使用教程)
- [Steam]SteamDirect开发者的使用参考
- window上使用GIT的个人经验(入门级)
- 多级分类,按用户配置可选-使用三组ListBox(参考taobao发布)
- 使用jekyll bootstrap在github上建立个人博客
- 我的mqtt协议和emqttd开源项目个人理解(5) - hook的使用,源码分析
- OpenCV2 使用分水岭算法对图像分割的个人理解 cv::watershed()
- Go 语言使用WaitGroup个人笔记记录
- 8.UBUNTU的Apt使用参考
- 关于Qt使用windeployqt发布相关问题解决办法--个人整理
- Altium Designer18 初步使用参考
- vmware,VirtualBox,kqemu使用个人感受