keil c51函数指针
Keil C51 中的函数指针和再入函数,函数指针与overlay
=====
调用树的保存
?? C51不把函数参数压栈(除非使用再入函数)。函数参数和全局变量被存入寄存器或固定的存储空间。这样阻止函数的再入。例如,一个函数调用它自己,它将覆盖它自己的参数或存储空间。函数的再入问题通过关键字“reentrant”来解决。函数指针的非再入函数的副作用,在执行中出现问题。
MAIN函数调用FUNC和FUNC_CALLER(根据调用树)。
用函数的指针来传递参数,调用树往往会出错。
=====
转???????这篇文章是由Keil C51 的英文文档翻译过来的,很多语句都是根据自己的理解翻译的,肯定还有许多地方需要推敲。希望读者能吸取到有用的部分,不要被误解了,自己多理解。
Overlay修改用于数据覆盖的调用树。如果在用户程序里使用了函数指针,或者使用了像实时操作系统中调度器那样的跳转(k 指的是指针方式的调用吗?),那么,修改程序调用树将是很有必要的。
混合编程:
函数名?????????????????????? 符号名????????? 解释viod func(void)????????????? FUNC??????????? 无参数传递,或不含寄存器参数的函数名不作改变???????????????????????????????????????????? 转入目标文件中,名字只是简单地转为大写形式
viod func(char)????????????? _FUNC?????? 带寄存器参数的函数名加入“_”字符前缀,它表明???????????????????????????????????????? 这类函数包含寄存器内的参数传递
viod func(viod) reentrant??? _?FUNC????????? “_?”表示可重入,它表明该行数包含栈内的参数传递。
====
将下面这篇的难点内容提到前面
使用函数指针的附加说明
?? 如果你在C51中使用函数指针编程,有几个附加的说明你必须注意。
参数列表的限制
?? 通过函数指针传递参数给函数必须把所有的参数存入寄存器。在大部分情况下,3个参数能够自动通过寄存器传递。在C51的用户手册中能找到传递参数进入寄存器的运算法则。但是并不保证,任何的3个数据类型可以传递。
? 因为C51在寄存器中传递3个参数,用于传递参数的存储空间是不被分配的,除非函数指向一个要求更多参数的函数。如果在那样的情况下,可以把参数混入一个结构体中,然后通过一个结构体指针传递参数。如果这样不可接受,你可以使用再入函数(看下面)。
?
调用树的保存
?? C51不把函数参数压栈(除非使用再入函数)。函数参数和全局变量被存入寄存器或固定的存储空间。这样阻止函数的再入。例如,一个函数调用它自己,它将覆盖它自己的参数或存储空间。函数的再入问题通过关键字“reentrant”来解决。函数指针的非再入函数的副作用,在执行中出现问题。
?? 为了保护尽量多的数据空间,连接器执行调用树的性能分析,决定一些存储空间被安全的覆盖。例如,如果你的应用中包含main 函数,函数a,函数b,函数c,并且main函数调用a,b,c,但是a,b,c之间没有互相调用。在你应用中的调用树见出现如下:
MAIN
??? +→ A
??? +→ B
??? +→ C
这样A,B,C的存储空间可以被安全的覆盖。
?
当调用树不能正确的建立,函数指针将带来问题。因为连接器不能决定函数之间的引用。在这个问题上,没有自动的解决方法。
?
下面两个源文件将解答这个问题,使问题容易明白。第一个源文件FPCALLER.C,包括一个函数,它通过一个函数指针(fptr)调用另一个函数。
?
FPCALLER.C????? // 第一个源文件FPCALLER.C? (文件名)
?void ?func_caller(long (code *fptr) (unsigned int))?????// (函数名)
{
????? ? unsigned char i;
???? ? for(i=0;i<10;i++)
?????? ?{
????????(*ftpr)(i);
??????? }
}
?
第二个源文件FPMAIN.C,包含C主函数和被func_caller调用的函数func。?????? 注意main函数调用func_caller,把func的地址作为参数传递给func_caller。
?
FPMAIN.C????? // 第二个源文件FPMAIN.C (文件名)
extern ?void func_caller (long (code *) (unsigned int));
int ?func (unsigned i