关于函数指针的两种调用方式解释与数组的类比

关于函数指针的两种调用方式解释与数组的类比

函数调用的两种方式

首先先定义一个函数指针:void (*p) (void);
第一种调用方式:(*p) ()
第二种调用方式:p()

先看效果:
在这里插入图片描述

原因解释

对于上图来说,先从指针赋值开始说,如果把指针赋值写成这样,不知道有感觉了没有
下面展示一些 内联代码片

p = myfun();
p = &myfun();

对于这两种赋值,实验现象是一样,这里提一句,有没有和数组名有点像
如果这两种赋值一一对应的话,就是如下,但是可以混用,这是和数组不同的地方
下面展示一些 内联代码片

p = myfun(); --------p();
p = &myfun(); -------(*p)();

下面的语言借鉴于18年前的大佬(有修改和删减):
C语言属于一种高级语言,所以它里面的类型都是概念上的类型;
C语言又号称中级语言,那是因为C语言的概念与底层实现结合过于紧密,并没有完全分开。最典型的就是数组和指针的互换。

下面展示一些 内联代码片

char  a[10];
char* p = a;

assert( p[3]==a[3] );
assert( *a==p[0] );

函数名就是所在模块在内存中的入口地址(一个常量),函数在概念上跟其他变量是一样的,都是一个独立的对象(函数模块),所以在概念上也是可以取地址的。
数组也是同一个道理,数组名代表的也是数组首地址,但我们还是可以取数组变量的地址。这就是因为数组在概念上也是一个独立的对象(声明数组a时,那一整块内存都是数组a的,这一整块内存就是一个独立的)。其他结构,比如说:类,联合什么的,都是同样的道理。
(*p)()是与概念上的函数指针相吻合的,取出一个函数模块指针对象所指向的函数模块,然后调用他;
p()是与实际实现时候相吻合的,本来一个函数指针的值就是一个函数模块的地址,这里就直接当函数模块的地址用了,这和直接使用**数组名[]**一样
加&和(*p)()只是为了维护概念和用法上和其他指针类型统一而已。不过对于数组的加点补充,对于数组名a,a与&a不尽相同,&a是整个数组的起始地始,而a是第一维第一个元素的起始地始,虽然位置一样,但赋值和取元素时结果是不一样的。
在这里插入图片描述

形象来比喻的话,把数组a比喻成一个大盒子,里面有很多个小盒子,&a就是把整个大盒子看成一个整体,取这个大盒子的地址,然后要存放这个大盒子的地址,那么这个指针类型就必须是这个大盒子的类型;a就是大盒子的第一个小盒子的地址,存放这个小盒子的地址的话,指针类型就是存放这个小盒子的类型

题外话

int (*PTRFUN) ( int aPara );
表示:定义了一个返回值为int类型,参数为一个int类型的函数指针

int () ( int aPara )
表示:表示了一个返回值为int类型,参数为一个int类型的函数指针的类型
可以用于强制类型转换,例如(int (
) ( int aPara ))Fun,意思是把Fun强制类型转化成一个返回值为int类型,参数为一个int类型的函数指针

typedef int (*PTRFUN) ( int aPara );
表示:定义了一个返回值为int类型,参数为一个int类型的函数指针的类型,这个类型的新名字为PTRFUN

如何理解(*(void)( * )() )0)();

把加粗部分看成一个整体,可以用上述的第二段来理解,或者用第三段来替换一下这样更明显,typedef void(*PTRFUN) ( ); 所有上述式子就成了
( * (PTRFUN)0)();
这下意思就明确了,把地址0强制转换成PTRFUN类型,并且取0地址里的值,调用存放在地址0里面的函数,这条语句用于解决计算机开机启动后,硬件读取首地址为0位置的子例程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值