概述
函数指针是C言语中几个难点之一。由于8051的C编译器的共同要求,函数指针和再入函数有更多的应战需求战胜。首要由于函数变量的传递。
典型的(绝大部分8051芯片)函数变量经过仓库的入栈和出栈指令来传递。由于8051只要有限的仓库空间(128字节或更少的64字节),函数变量有必要经过不同的方法进行传递。
8051的PL/M-51编译器,介绍在固定的存储空间存储变量的方法。当运用连接器时,程序树立一个调用树,计算出函数变量的互斥空间,然后掩盖它们。这便是连接器的“OVERLAY”指令。
由于PL/M-51不支持函数指针,所以不能完成直接函数调用。可是,C言语中存在这样的问题。连接器知道哪块空间用于存储直接函数的变量。怎样直接参加函数进入调用树?
本文解说在C51编程中,怎样有用运用函数指针。特别地,评论如下几个论题:
分配常量地址给一个指针;
界说函数指针;
C51中函数指针问题;
运用OVERLAY指令确认调用树;
再入函数的指针;
固定地址的指针
你很简单的给函数指针分配一个数字地址。有许多原因需求这样做。例如,你需求复位方针。你能够设置函数指针为0000H去完成。
你能够运用规范C言语的类型映射特色,映射0X0000指针指向地址0的函数。例如,当你编译如下C代码….
((void (code *) (void))0x0000) ();
…编译器发生如下如下代码:
;FUNCTION main (BEGIN)
;SOURCELINE#3
0000120000LCALL00H
;SOURCELINE#4
000322RET
; FUNCTION main (END)
这正是咱们希望的:LCALL0
把一个数字常量映射成一个函数指针是一件很杂乱的工作。下面关于上面的函数调用的各部分的描绘,将协助你怎样更好的运用它们。
在上面的函数调用中,(void ( *) (void))是数据类型:一个不带参数且回来void的函数指针。
0x0000是一个映射地址。经过类型映射,函数指针指向地址0x0000。留意咱们把一个圆括号放在数据类型和0x0000后边。假如咱们只是想映射0x0000成为函数指针,这是不必要的。可是,由于咱们将引证这个函数,这些圆括号是必要的。
映射一个数值常量成为指针和经过指针调用函数是不同的。为了完成这个,咱们有必要指定一个变量表。这便是为什么在此行的后边有一个()。
留意上面表达式中的一切圆括号都是有必要的。分组和优先级是很重要的。
上面不带参数的函数指针和带参数的函数指针的仅有不同是数据类型和变量列表。例如,下面的函数调用…..
((long (code *) (int int int ) 0x8000)(1,2,3);
声明一个函数,地址在0x8000,接纳3个int型参数,回来long型成果。
不带参数的函数指针
指向函数的函数指针是可变的。函数的地址是一个可变的数值。例如,下面的函数指针的声明….
void (*function_ptr) (void);
是一个调用function_ptr的指针。运用下面的代码调用function_ptr函数。
(*function_ptr ) ();
由于函数没有参数传送,所以参数列表时空的。
当界说变量的时分,函数指针能够被分配地址:void (*function_ptr) (void) = another_fuction;或许在程序履行进程中被分配,function_ptr = another_fuction;
留意,有必要分配一个地址给函数指针。假如没有分配,函数指针将有一个0值(假如你命运好),或许有一些你彻底不知道的数值,依赖于你的数据存储区的运用情况。当你直接的调用一个函数经过函数指针,假如函数指针没有初始化,你的程序将是紊乱的。
为了声明一个带回来值的函数指针,在声明进程中你有必要指定回来值的数据类型。例如,下面的声明改变了上面的函数指针的声明,回来一个float 数据。
float(*function_ptr) (void) = another_fuction;
带参数的函数指针
带参数的函数指针与不带参数的函数指针是类似的。例如:
void (*function_ptr) (int, long,char); 一个函数指针,带一个int参数,带一个long参数,带一个char参数。运用下面的代码调用函数。
(*function_ptr) (12, 34L,‘A’);
留意,函数指针只是能够指向小于等于3个参数的函数。这是由于,直接调用函数时,参数有必要保存在寄存器中。关于超越3个参数的函数指针的信息,在再入函数中介绍。
运用函数指针的附加阐明
假如你在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的存储空间能够被安全的掩盖。
当调用树不能正确的树立,函数指针将带来问题。由于连接器不能决议函数之间的引证。在这个问题上,没有主动的处理方法。
声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/chuanganqi/257392.html