函数指针的类型转换

1、铺垫

在分析上面的语句前,我们先从简单的入手。先来区别和理解下面这两个定义。

float  *g();   和 float  (*h) ();

直接上答案:由于( )结合的优先级别高于*,所以g先和后面的( )结合,构成一个函数,该函数的返回值是一个指向float 数的指针。同理,h是一个函数指针,它所指向的函数的返回值是一个浮点数。

当我们知道如何声明一个给定类型的变量,那么不难得出该类型的类型转换:只需要把声明中的变量名和声明末尾的分号去掉,然后将剩下的部分用一个括号整个“封装”起来。最简单的例子比方说我们以前学过的强制转换   (int) value这类的,但是我们现在稍微复杂一些。如下:

 float  (*h) ();   表示h是一个指向返回值为浮点类型的函数的指针,所以有

(float  (*) () )   表示一个“指向返回值为浮点类型的函数的指针”的类型转换  

 

2、理解

有了上面的铺垫之后,我们就开始理解(*(void (*)())0)();这个语句。

1) (void (*)())  里面的这个和铺垫的一样,是一个类型转换,表示一个“指向返回值为void类型的函数的指针”的类型转换。

2)   (void (*)())  0  这是表示将常数0转换为“指向返回值为void的函数指针”类型。

3)    有了1) 和 2)的理解之后,我们就明白,0是一个函数指针,它指向的函数的返回值类型为void,这样就比较好办了,那我们就按照使用指针变量的方法去理解它。我们使用一个指针变量的时候,前面会带一个*号,同理,对于这样一个函数指针,我们在调用它的时候。也类似地这么调用,就是(*(void (*)())0)();这就分析完了。

 

3、补充

这个例子主要运用在计算机地址方面,比方说arm芯片一上电的时候,是从0地址处开始执行程序。而要对各个状态字进行配置或者存入某个内存块的时候,处理的方法也都是把一个常数(也就是这个地址)转换成一个指针类型,然后对这个指针进行操作就能对该地址进行操作,这方面在嵌入式的配置方面见得比较多。

我之所以说这个例子对我有帮助是这样的,如下:。

pos == IOFPGA_DO_DATA_ADDR(iofpga_if_get_dod_addr(), pfifo) ;

#define IOFPGA_DO_DATA_ADDR(base, reg)((unsigned int)&(((struct st_iofpga_do_data *)((int)base))->reg))

右边的表达式我一看就知道在干嘛了(因为在此之前我看过标题的例子),我们看一下右边的表达式对这base和reg这两个形参做了什么事情,很明显嘛:

1)首先把base强制转换为int类型,注意,它是一个常数。

2)结合上面的例子分析,(struct st_iofpga_do_data *)((int)base) 和上面的例子用法一样,就是把一个常数转换成一个指针,这      里是转换成自定义的结构体指针。

3)((struct st_iofpga_do_data *)((int)base))->reg)  把这个常数转换成结构体指针之后,在这个结构体中找到传入的reg成员。

4)  &(((struct st_iofpga_do_data *)((int)base))->reg))  找到该结构体里面的这个成员之后,用&取其地址

5) (unsigned int)&(((struct st_iofpga_do_data *)((int)base))->reg)  &取到这个成员的地址之后,强制转换为(unsigned int)类型

6)分析完毕....

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值