</p> //自行包含头文件void MyFun(int x); //此处的申明也可写成:void MyFun( int );typedef void (*FunType)(int ); //这样只是定义一个函数指针类型FunType FunP; //然后用FunType类型来申明全局FunP变量
5 I0 x, K4 z3 b N$ @! K% G int main(int argc, char* argv[])
7 _5 p; a4 D+ U# |: w& ]* M7 {1 ] { //FunType FunP; //函数指针变量当然也是可以是局部的 ,那就请在这里申明了。 $ W* P; @. G) {0 t' \; i1 ]* @
MyFun(10);FunP=&MyFun;(*FunP)(20); " y: A4 H' x; g Z; l- Y0 C7 A- Z
return 0;} , D- F; I; B; i2 k' j+ _' }( L
void MyFun(int x) 0 R! ^' G, c4 a# m, J3 S; F
{ printf(“%d\n”,x);}看黑体部分:首先,在void (*FunType)(int ); 前加了一个typedef .这样只是定义一个名为FunType函数指针类型,而不是一个FunType变量。 3 a' P! T. x: v* H
然后,FunType FunP; 这句就如PINT px;一样地申明一个FunP变量。 3 B- f+ k; ^+ }/ x! [! f
其它相同。整个程序完成了相同的事。 J- w, a4 q0 S+ A' S7 M
这样做法的好处是:有了FunType类型后,我们就可以同样地、很方便地用FunType类型来申明多个同类型的函数指针变量了。如下:FunType FunP2;FunType FunP3;//……
0 P9 V, \- O, E' M5 P 六 函数指针作为某个函数的参数既然函数指针变量是一个变量,当然也可以作为某个函数的参数来使用的。所以,你还应知道函数指针是如何作为某个函数的参数来传递使用的。
5 o" c- `# R# R _& U 给你一个实例:要求:我要设计一个CallMyFun函数,这个函数可以通过参数中的函数指针值不同来分别调用MyFun1、MyFun2、MyFun3这三个函数(注:这三个函数的定义格式应相同)。 7 [- x' W" Q$ k. F& Q1 G
实现:代码如下://自行包含头文件void MyFun1(int x);void MyFun2(int x);void MyFun3(int x);typedef void (*FunType)(int ); //②。 定义一个函数指针类型FunType,与①函数类型一至void CallMyFun(FunType fp,int x); 8 x/ n* r6 V5 V$ E7 J4 m
int main(int argc, char* argv[])
3 r- ?+ S# }, E5 z* Q { CallMyFun(MyFun1,10); //⑤。 通过CallMyFun函数分别调用三个不同的函数CallMyFun(MyFun2,20);CallMyFun(MyFun3,30);} void CallMyFun(FunType fp,int x) //③。 参数fp的类型是FunType. { fp(x);//④。 通过fp的指针执行传递进来的函数,注意fp所指的函数是有一个参数的} void MyFun1(int x) // ①。 这是个有一个参数的函数,以下两个函数也相同{ printf(“函数MyFun1中输出:%d\n”,x);} void MyFun2(int x)
6 t+ _1 r! G* K3 F# U, c) l/ f/ } { printf(“函数MyFun2中输出:%d\n”,x);} void MyFun3(int x) $ A6 Y; f; j! s( g: P" [' V+ v2 g u. u
{ printf(“函数MyFun3中输出:%d\n”,x);}输出结果:略
& n, }( m. d1 E' ~+ h 分析:(看我写的注释。你可按我注释的①②③④⑤顺序自行分析。) 6 |9 D9 i3 O! C! R2 T
七 地址跳转void(*reset)(void)= (void(*)(void))0. void(*reset)(void)就是函数指针定义,(void(*)(void))0是强制类型转换操作,将数值“0”强制转换为函数指针地址“0”。
/ z: K; B8 o% R# @ 通过调用reset()函数,程序就会跳转到程序执行的“0”地址处重新执行。在一些其他高级单片机Bootloader中,如NBoot、UBoot、EBoot,经常通过这些Bootloader进行下载程序,然后通过函数指针跳转到要执行程序的地址处。
. j% c9 _7 F z0 X 1 void (*theUboot)(void);……
# ~: h( t9 m! E' R1 R6 l: R theUboot = (void (*)(void))(0x30700000);theUboot();……
# V" F+ u4 }2 b0 L' W2 ^. D* ?, M; e 2 (*(void (*)(void))(0x30700000))();强制类型转换,将一个绝对地址转换为一个函数指针,并调用这个函数以跳转到前面提到的绝对地址。 : T0 c% x7 j! g- D5 O2 {; x( K
翻译成汇编就是:mov r0,0x30700000;mov pc,r0对于(*(void (*)(void))(0x30700000))();可以这样理解首先(void( * )(void) )是一个强制类型转换符,他将后面的0x30700000这个无符号整数强制转化为一个函数指针,该函数指针所指向的函数入口参数为 void,返回值也是void . 如果到这步你看懂了,那么设(void (*)(void))(0x30700000)为 fp; 那么上面的表达式就可以简化为 (*fp)(); OK,这下就清楚了吧,我们将上面转化好的函数指针进行引用(也就是调用函数指针指向的函数)。 |