通过函数指针实现程序跳转

函数指针的定义

首先看指针的定义,指针是指向某个变量的地址,实际不占用内存空间,就是个地址。例如:

int *p;   //p指向某个int变量
int a=123;//int类型的变量a值为1,地址为编译器自动分配。
p=&a;     //p指向变量a,p为变量a的地址
          //此时,假设a的地址是0x1000,那么*p=123,p=0x1000。

在说函数指针定义之前,我们再引申一下,也是我以前从来没想过的。
变量a的名字其实对于MCU没有意义,没有地方保存a的名字‘a’,a这是对于我们(开发者)来说的一个好记的代号,在MCU中的表现就是,地址0x1000中存放数据123。那么就可以通过下面的方法直接对该地址进行赋值,而不通过变量a这个名字。

(int *)0x1000=123;

虚拟的p还是个指向int的指针,p指向的地址还是0x1000,只不过这个过程中没有指针p这个名字了,也没有变量a这个代号了。
这条语句正确解读应该是首先将0x1000强制类型转换为指针,然后对其赋值。


实测发现,应该调用如下

*(int *)0x1000=123;

并且这是一条语句,并不是声明或定义,也就是0x1000地址里事先并没有存放123,而是执行这一条语句后才赋值。program flash中会同时保存0x1000和123。


再来看函数指针,顾名思义,就是指向函数的指针,和普通指针一样,函数也是有类型的,有/无返回值,有无参数。先来看比较简单的无返回值值无参数的情况。
定义一个函数指针pfun:

void fun()
{
printf("123\n");
}
void(*pfun)() = &fun; //定义无返回值无参数的函数指针pfun,指向fun函数的入口地址;
(*pfun)(); //调用该函数指针,其值为指向函数fun的入口地址;

或者如下也是一样的效果:

void(*pfun)()=fun;  //定义函数指针pfun,指向fun函数
pfun();  //调用该函数指针,即fun的入口地址

最终要达到调用fun()的效果就必须索引到fun()函数的入口地址。

再下一步,实现让程序跳转到绝对地址0x100000去执行。可以这样想,如果有一个函数,该函数的入口地址是0x100000,那么就可以通过调用该函数来实现跳转。但是事实上没有这个函数,于是就可以定义一个函数指针void(*fun)();
将该指针指向地址0x10000,即强制类型转换:

(void(*)())0x10000;

现在上式就是一个指向0x10000地址的函数指针,或者这样解释更好理解,这是一个函数指针,指向一个虚拟的函数fun,fun函数的入口地址为0x10000
再下一步就是调用这个函数指针指向的函数

(*((void(*)())0x10000))();

需要理解的关键点是,一是函数指针的定义和使用方法,二是函数名本身就是一个入口地址,例如通过uint16 i = (uint16)main语句就可以把main函数的入口地址赋值给i(实测有效)。


实测发现
i=(uint16)main和i=(uint16)(&main)都是取main的首地址;
(((void()())0x40000))();和(((void(*)())0x40000))();都可以实现程序跳转;
但是所有方式在main()中都无法实现跳转或软件复位,均是在boot程序中可以实现,尚无找到原因,猜测和中断开启有关。


https://blog.csdn.net/judyge/article/details/49824889

int main(void)
{
void (* my_function)(void);
//int *my_address = 0x8000;
my_function = (void (*)()) (0x8000);
my_function();
}
//
typdef void (*pStartType)(void);
pStartType pStart;
{
...
pStart = (pStartType)(0x40000);
pStart();
...
}

上面两种方式是相同的效果,在另一篇笔记里会重点谈一下typedef和函数指针的应用。


Update:
在DevC++里测试了一下四种通过函数指针调用函数的方式,都是可以的。如下:

#include <stdio.h>
#include <stdlib.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

void fun()  
{  
    printf("我调用成功了\n");  
}  
int main()  
{      
    printf("%s","test1");
    void(*pfun)() = fun;  
    pfun();  
    printf("%s","test2");
    pfun = fun;
    (*pfun)();
    printf("%s","test3");
    pfun = &fun;
    pfun();
    printf("%s","test4");
    pfun = &fun;
    (*pfun)();

    system("pause");  
    return 0;  
} 

这里写图片描述

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值