函数指针

来源:互联网 发布:师洋淘宝骂人截图 编辑:程序博客网 时间:2024/06/03 05:06

理解函数指针

为便于理解,你可以这样解释:
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 + yvoid 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);}

这是一个简单的例子。运行这段代码,你会看到每个函数指针都会执行,知识会受到一些关于字符转换的警告。但是,这些函数指针都能正常工作。
  1. 在第20行,add作为函数名,返回这个函数的地址,它被隐式的转换为一个函数指针。我之前提到过,在函数指针被要求当作输入的地方,就能够使用函数名。
  2. 在第21行,解引用符作用于add之前,即*add,在返回在这个地址的函数。之后跟函数名一样,它被隐式的转换为一个函数指针。
  3. 在第22行,取地址符作用于add之前,即&add,返回这个函数的地址,之后又得到一个函数指针。
  4. 23到24行,add不断地解引用自身,不断返回函数名,并被转换为函数指针。到最后,它们的结果都和函数名没有区别。

显然,这段代码不是优秀的实例代码。我们从中收获到了如下知识:
其一,函数名会被隐式的转换为函数指针,就像作为参数传递的时候,数组名被隐式的转换为指针一样。在函数指针被要求当作输入的任何地方,都能够使用函数名。
其二,解引用符*和取地址符&用在函数名之前基本上都是多余的。

参考

http://hi.baidu.com/guxue365/blog/item/dc93c52aff9b489c023bf612.html

C语言函数指针基础

 

原创粉丝点击