函数指针 && 返回函数指针的函数的一些姿势

来源:互联网 发布:php echo 数组 编辑:程序博客网 时间:2024/04/28 17:17
函数指针一些知识
(1) ,  在mj下拉刷新中遇到了定义的一个宏,看起来比较晦涩,如下
#define msgSend(...) ((void (*)(void *, SEL, UIView *))objc_msgSend)(__VA_ARGS__)
其实就是把objc_msgSend函数指针强制转换成另一种类型((void (*)(void *, SEL, UIView *)))的函数指针,
所以这个宏表示的就是一个个函数指针
(void (*)(void *, SEL, UIView *))这一坨其实表示的是一个函数指针(指向一个函数的指针,这个函数返回值为void,有3个参
数),前面这一坨的意思就是把objc_msgSend这个函数指针转换成这一坨的指针类型。这样的好处就是可以限制这个宏接受的3个参数必须是这一坨中的3个参数。
调用的时候,可以这么调用:
objc_msgSend(ivar1,ivar2,ivar3);
这与(*objc_msgSend)(ivar1,ivar2,ivar3);是等价的。
下面分析为什么他们是等价的?
void (*funcPtr)(); // 这是一个函数指针
void *funcPtr();  //  这是一个函数
主要取决于运算符的优先级,funcPtr是应该先与坐边的*结合还是与右边的()结合,因为函数运算符()的优先级要高于单目运算符*,所以如果没有括号那就先与()结合,那么它就是一个函数。

在《C陷阱与缺陷》中有这样一段描述:

fp是一个函数指针,那么*fp就是该指针所指向的函数,所以(*fp)()就是调用该函数的方式。ANSI C标准允许程序员将上式简写为fp(),但是一定要记住这种写法只是一种简写形式。

在表达式void (*func)()中,*func两侧的括号非常重要,因为函数运算符()的优先级要高于单目运算符*。如果*func没有括号,那么*func实际上与*(func())的含义完全一致,ANSI C把它写作*(*(fp)())的简写形式。

根据以上的描述,我们似乎可以得到这样一个结论:

       1. func是一个函数指针

       2. func()(*func)()的一个简写形式

       3. &func&(*func)的简写形式

如果这样理解正确的话,那么上面那段代码就顺理成章了。用宏定义了一个函数指针,然后使用的时候展开宏,就是调用一个函数指针,也就等同于调用这个函数objc_msgSend,因为objc_msgSend(...) 是等同于(*objc_msgSend)(...)的。

下面是一个面试题:
void * (*(*fp1)(int))[10]; // 表示的什么?

我们从里向外一点一点分析,首先(*fp1)(int),这说明fp1是一个函数指针,它有一个int类型的参数;然后我们来找这个函数指针类型的返回值,注意到*(*fp1)(int),所以我们可以断定它的返回值是一个指针,指针指向什么呢?

我们可以看到最外层剩余的部分是void* [10],因此这个函数的返回值是一个指针,这个指针指向一个包含十个void*类型数据的数组。

综上:fp1是一个函数指针,它所指向的函数有一个int类型的参数,并且这个函数的返回值是一个指针,这个指针指向一个包含10void*元素的数组。
总结最重要的一点:
        (*fp1)(int)说明它是一个函数指针,这个好理解,然后再与左边*结合*(*fp1)(int),说明它的返回值是一个指针,就如同:
int *func()说明这个函数指针的返回值是一个指针,指针的类型为int。
这个如果理解就好办了,说明返回值是一个指针,那这个指针的类型是什么呢?就是void *[10],一个包含10个空指针的数组。
如果变一下,
int* (*fp2)(int)[10]; // 表示的什么?
首先,fp2是一个函数指针,很好理解,然后是先与左边的*结合还是与右边的[10]结合呢?根据运算符优先级,[]高于*,因此
函数的返回值是一个数组:int *[10], 而不一个指针。在C语言里面,数组是不能直接作返回值的,作为返回值的时候,必须转换成指针的,因此,这个语句会报错:
error: Function cannot return array type " int *[10] "

如果再变一下,加一个括号,
int(* (*fp3)(int))[10]; // 表示的什么?
首先,fp2是一个函数指针,很好理解,因为加了一个括号,所以函数的返回值是一个指针,那这个指针指向什么呢?
指向int[10](包含10个整型数据的数组)。这样就没有问题的,因为函数的返回值是一个指针,指向一个数组。

/*-------------------------------------------------------------------------*/
void (*funcPtr)(); // 这是一个函数指针,因为(*funcPtr)优先结合,表示这是一个指针
void *funcPtr();   // 这是一个指针函数因为函数括号()优先级高于*,所以这是一个函数
int  *a[10];       // 这是一个指针数组,因为[] 优先级高于*,所以这是一个数组
int  (*a)[10];     // 这是一只数组指针因为()优先级高级[],所以这是一个指针
/*-------------------------------------------------------------------------*/

更具体的函数指针:http://blog.csdn.net/itianyi/article/details/42456753


(2),  在新行情重构中,遇到了调用的一个函数signal(信号量),也比较晦涩,如下:
void(*signal(intvoid (*)(int)))(int);
这是一个返回函数指针的函数。
首先, signal按优先级先与函数()符号结合,那么它就是一个函数,
然后,再与左侧的*结合,表示返回值是一个void(*)(int)类型。如果按下面这么写就容易理解了:
typedef void(*PF)(int);
PF signal(int, void (*)(int))
更详细的返回函数指针的函数:http://blog.csdn.net/itianyi/article/details/42455953
0 0
原创粉丝点击