函数调用的两种方式
首先先定义一个函数指针: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位置的子例程