理解函数指针
为便于理解,你可以这样解释:
typedef void(* Fun)(void) Fun
类似于
typedef int INT
Fun在声明以后,可以把它当作数据类型声明其他变量
Fun的确切意义是一个函数指针类型,该函数没有参数且无返回值
定义了一个int类型的变量i;
而这样
typedef INT int;
表示用户自己定义了一个整型数据类型INT,实际上就等同于int
所以:INT ii;
同上,表示定义了一个int类型的变量ii;
同样的:
void (*pFn)(void)
定义了一个函数指针,该函数指针指向 类似于 void Foo(void)函数的函数入口地址
而这样:
typedef void (*Fun)(void)
表示用户自己定义了一个函数指针数据类型
而
Fun pf;
表示定义了一个函数指针pf,改函数指针指向类似于void Foo(void)的函数
函数名和地址
一个函数名(或称标签),被转换成了一个指针本身。这表明在函数指针被要求当做输入的地方,就能够使用函数名。这也导致了一些看起来很糟糕的代码却能够正确的运行。
#include <stdio.h>
// 函数原型
void add(char *name, int x, int y);
// 加法 x + y
void add(char *name, int x, int y) {
printf("%s gives: %d\n", name, x + y);
}
// main函数调用
int main() {
// 一些糟糕的函数指针赋值
void (*add1Ptr)(char*, int, int) = add;
void (*add2Ptr)(char*, int, int) = *add;
void (*add3Ptr)(char*, int, int) = &add;
void (*add4Ptr)(char*, int, int) = **add;
void (*add5Ptr)(char*, int, int) = ***add;
// 仍然能够正常运行
(*add1Ptr)("add1Ptr", 10, 2);
(*add2Ptr)("add2Ptr", 10, 2);
(*add3Ptr)("add3Ptr", 10, 2);
(*add4Ptr)("add4Ptr", 10, 2);
(*add5Ptr)("add5Ptr", 10, 2);
// 当然,这也能运行
add1Ptr("add1PtrFunc", 10, 2);
add2Ptr("add2PtrFunc", 10, 2);
add3Ptr("add3PtrFunc", 10, 2);
add4Ptr("add4PtrFunc", 10, 2);
add5Ptr("add5PtrFunc", 10, 2);
// 好吧,这也可以运行
(**add1Ptr("add1PtrPtr", 10, 2);
}
这是一个简单的例子。运行这段代码,你会看到每个函数指针都会执行,知识会受到一些关于字符转换的警告。但是,这些函数指针都能正常工作。
- 在第20行,add作为函数名,返回这个函数的地址,它被隐式的转换为一个函数指针。我之前提到过,在函数指针被要求当作输入的地方,就能够使用函数名。
- 在第21行,解引用符作用于add之前,即*add,在返回在这个地址的函数。之后跟函数名一样,它被隐式的转换为一个函数指针。
- 在第22行,取地址符作用于add之前,即&add,返回这个函数的地址,之后又得到一个函数指针。
- 23到24行,add不断地解引用自身,不断返回函数名,并被转换为函数指针。到最后,它们的结果都和函数名没有区别。
显然,这段代码不是优秀的实例代码。我们从中收获到了如下知识:
其一,函数名会被隐式的转换为函数指针,就像作为参数传递的时候,数组名被隐式的转换为指针一样。在函数指针被要求当作输入的任何地方,都能够使用函数名。
其二,解引用符*和取地址符&用在函数名之前基本上都是多余的。
参考
http://hi.baidu.com/guxue365/blog/item/dc93c52aff9b489c023bf612.html