关于typedef函数指针的用法和理解
在此记录下所理解的和具体用法,以防忘记了又重复找资料
1、什么是函数指针
如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
函数指针的定义方式为: 函数返回值类型 (* 指针变量名) (函数参数列表);
例如 int(*p)(int, int);
注意的是,指向函数的指针变量没有 ++ 和 - - 运算
简单用法:
int fun(int x); //声明一个函数
int (*p) (int x); //定义一个函数指针
p = Func; //将Func函数的首地址赋给指针变量p
这个其实感觉和数组差多,int a[10]; int * p ; p = a;-------自我感觉可以结合起来一起记
2、用typedef来定义类型使用
2.1 最简单的用法
形式1:typedef 返回类型(*新类型)(参数表)
typedef char (*PTRFUN)(int);
PTRFUN pFun;
char Fun(int a){ return;}
void main()
{
pFun = Fun;
(*pFun)(2); //pFun(2);这样写也可以编译通过并正确
}
typedef的功能是定义新的类型。第一句就是定义了一种PTRFUN的类型,PTRFUN这个类型定义出来的变量将会是一个拥有int类型为参数并返回char类型的函数的指针。 第二行的代码使用这个新类型定义了变量pFun.第三行的代码是实现了一个函数Fun。最后在main函数里面直接像变量赋值一样给pFun赋值Fun。
2.2大佬的例子(这个列子就当学习怎么使用typedef了,底部有链接地址可以去看他的文章):
#include <stdio.h>
#include <assert.h>
typedef int (*FP_CALC)(int,int);//定义一个函数指针类型
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return b ? a/b : -1;
}
//定义一个函数,参数为op,返回一个指针,该指针类型为拥有两个int参数、返回类型为int的函数指针。它的作用是根据操作符返回相应函数的地址
FP_CALC calc_func(char op)
{
switch( op )
{
case '+':
return add;
case '-':
return sub;
case '*':
return mul;
case '/':
return div;
default:
return NULL;
}
return NULL;
}
//s_calc_func为函数,它的参数是 op, 返回值为一个拥有两个int参数、返回类型为int的函数指针
int (*s_calc_func(char op)) (int , int)
{
return calc_func(op);
}
//最终用户直接调用的函数,该函数接收两个int整数,和一个算术运算符,返回两数的运算结果
int calc(int a, int b, char op)
{
FP_CALC fp = calc_func(op);
int (*s_fp)(int,int) = s_calc_func(op);//用于测试
assert(fp == s_fp);// 可以断言这两个是相等的
if(fp)
return fp(a,b);
else
return -1;
}
void main()
{
int a = 100, b = 20;
printf("calc(%d, %d, %c) = %d\n", a, b, '+', calc(a, b, '+'));
printf("calc(%d, %d, %c) = %d\n", a, b, '-', calc(a, b, '-'));
printf("calc(%d, %d, %c) = %d\n", a, b, '*', calc(a, b, '*'));
printf("calc(%d, %d, %c) = %d\n", a, b, '/', calc(a, b, '/'));
}
2.3 最后在来一个不好理解的例子,在上一个例子的基础上在加了一点
我们要申明一个这样的函数:
void (*signal( int, void(*)(int) ) (int);
这个可以分为2部分来看 ,将signal( int, void(*)(int) )
用 p 代替,则变成了void(*p)(int);
这样看起来是不是就很清晰了,不过这时候一定要注意p是函数,void(*) (int)是这个函数的返回值,
千万不要把p认为是函数指针了,函数p的返回值为一个拥有1个int参数、返回类型为void的函数指针。
然后我们再来看signal( int, void(*)(int) ) ,signal是一个拥有2个参数的函数,一个参数是int,
另外一个参数比较特殊,是一个拥有1个int参数、返回类型为void的函数指针。
我们再用typedef简化上面的函数申明:
typedef void (*HANDLER)(int);
HANDLER signal(int,HANDLER);
补充:其实要理解typedef函数指针的用法,更应该要去理解函数申明(*(void(*) ())0)()
------这是什么?
这是《C Traps and Pitfalls》这本经典的书中的一个例子。分析:
第一步:void(*) ()
,可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。
第二步:(void(*) ())0
,这是将0强制转换为函数指针类型,0是一个地址,也就是说一个函数存在首地址为0的一段区域内。
第三步:(*(void(*) ())0)
,这是取0地址开始的一段内存里面的内容,其内容就是保存在首地址为0的一段区域内的函数。
第四步:(*(void(*) ())0)()
,这是函数调用。