函数指针一些知识
(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
类型的参数,并且这个函数的返回值是一个指针,这个指针指向一个包含10
个void*
元素的数组。
总结最重要的一点:
(*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(
int
,
void
(*)(
int
)))(
int
);
这是一个返回函数指针的函数。
首先, signal按优先级先与函数()符号结合,那么它就是一个函数,
然后,再与左侧的*结合,表示返回值是一个void(*)(int)类型。如果按下面这么写就容易理解了:
typedef void(*PF)(int);
PF signal(int, void (*)(int))
更详细的返回函数指针的函数: http://blog.csdn.net/itianyi/article/details/42455953