首先回顾一下函数指针,函数指针是指向函数的指针,不同于函数返回的指针类型数据,比如 int* (*p)(); 这句话就是声明一个函数指针p,他指向一个"返回值类型为指向整型数据的指针类型的函数"。也就是声明普通的指针类型变量我们是写上类型名后面接*,而声名函数指针类型我们是写函数的返回值类型后面括号里面写*接函数指针变量名,再接()象征形参列表,如果是需要传参的函数,还要在里面写上参数类型,然后后面写不写形参都可以,类型声明而已,能不写就不写吧。或者这样想:"声明普通指针类型是把*放在后面,而声明函数指针类型是把*放在返回值类型和参数列表之间。并且加括号"。至于为什么要用括号把*p包起来,是因为最右面空括号的优先级比*高,也就是说*p() 等同于*(p())。
然后再说函数名,函数名代表的含义是指向该函数的指针,这和数组名是指向数组的指针是类似的道理。
然后就是如果我要通过p调用某个函数,那么上面定义完了p之后,将他赋值为那个函数的函数名,比如
这边第16行是定义的同时用fun初始化了一个函数指针p,第17行是通过p调用了fun。这里注意写p或者*p都一样。这一点我不懂,只是知道这个现象。有人说*p是取值,取到第一个值,因为函数里首地址上第一个数据本来就也是首地址,所以正好*p也是首地址,和p一样,但我觉得不是因为这个,因为*p应该是取值取整个函数,而不是取首地址上存储的数据成员。
关于这一点,本书作者倾向的是用*p调用函数,并且说:
既然大牛这么说,那就不去管这个了,知道二者通用就好吧。
上述代码的输出应该不难看出,是:
下面进入正题,叫函数指针的强制类型转换书中扔出一个问题:
(*(void(*)())0)();这句话是什么意思?
结论是把整形0强制转换为void返回值的函数的函数指针类型并且通过这个函数指针取调用此处的函数,此处,就是0处,就是地址0处。在地址0 处有一个函数需要被调用,但是如果重新定义一个函数指针,假设被默认初始化为存储位置为0(我猜应该不会,因为全局下的指针应该被初始化为NULL才对)虽然也能调用存储位置为0的那个函数,但是为了调用一次函数而定义一个变量,这种行为不值当,这个变量称为"哑变量"。
作者遇到这个问题的时候还没有typedef用法,用了强制类型转换解决了,作者是这样讲解的:
比如声明int 写成 int a; 那么强制转换成int就把a 去掉,写成(int)
那么声明函数指针写成void (*fp)();那么强制转换就把fp去掉,写成(void (*)())后面接个0,就是把0转换为了函数指针,套括号再接形参列表括号接分号,就是调用了0指向的函数。为什么要套括号再接形参列表的括号?还是因为括号的优先级比*高,注意上图那个33是怎么输出来的,那就是不套括号的后果。
总结:函数指针的强制类型转换运算符是函数指针声明写法去掉变量名,最外层套括号。
转换谁就在右面接上谁。



