C语言中函数指针的声明及使用

函数指针一般的声明方式为:

1
Return (* pf)(Params);

其中Return代表返回值的类型,Params代表函数参数列表,如下面两个比较简单的声明:

1
2
void (* pf1)(int, char *);
int * (* pf2)(void);

使用的时候可以使用以下两种等价的赋值及调用方式:

1
2
3
4
5
6
7
// Assign
pf = FunctionName;
pf = &FunctionName;

// Call
pf();
(*pf)();

更为复杂一点的问题是,如果一个函数指针作为函数的参数与函数的返回值时该如何进行声明呢?

作为函数参数的情况比较简单,像这样处理即可:

1
2
3
4
5
6
void Fun(void (*)(int, int), int, int);

void Fun(void (* pf)(int, int), int a, int b)
{
return pf(a, b);
}

这个例子中,声明并定义了一个函数Fun(),这个函数接受3个参数,后两个参数为int,第一个参数的类型是void (*)(int, int),这是一个函数指针,指向一个返回值为void,参数为两个int的函数。


然而如何处理函数指针作为返回值的情况呢?标准库<signal.h>中的signal()函数就是一个这样的函数,其声明形式如下:

1
void (* signal(int sig, void (* handler)(int)))(int);

这个函数声明一眼看过去不是很好懂,下面来仔细分析一下。

如果我们要声明一个整形变量a,可以这样写:

1
int a;

如果要改为声明一个返回值为整形的函数fun(),可以视为只要将声明变量时使用的a改为fun()即可,即

1
int fun();

用同样的思路来分析声明一个返回值为函数指针的函数的声明方法,只要将函数指针声明中的变量名部分换为函数体即可。用实例分析一下:

1
void (* pf)(int);

这里面pf是一个函数指针,指向一个输入参数为int,返回值为void的函数。将其中的pf换为一个函数fun(),即

1
void (* fun())(int);

这样就得到了一个返回值为函数指针的函数fun(),它返回的函数指针其实就是上面的pf

理解了这样的声明方式后再来看signal()函数的声明就不那么难理解了。先看最里层:

1
void (* handler)(int)

这是一个函数指针handler,带一个int参数,返回值为空。

再向外一层:

1
signal(int sig, void (* handler)(int))

这是一个函数signal(),其参数为一个整形和一个函数指针。那这个函数的返回值是什么呢?由上面的分析易知,也是一个函数指针,这个函数指针的原型是这样的:

1
void (* Returnpf)(int);

对比Returnpfhandler的声明,可以看到二者是完全一样的。这时候就可以利用typedef这个好东西来简化之前那个复杂的signal()函数的声明了,具体做法如下:

1
2
3
4
5
void (* signal(int sig, void (* handler)(int)))(int);

typedef void (* sighandler_t)(int);

sighandler_t signal(int sig, sighandler_t handler);

其中第1行与第5行的声明是完全等价的,使用第5行这种声明方式就显得直观多了。


最后编写了两个简单的测试程序来进一步熟悉下函数指针的使用方法。

不使用typedef的版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>

// Function declaration
void PrintStr(char *(*)(void));
char *(* Run(int, int, int (*)(int, int)))(void);

char * Msg1(void)
{
return "Great than 0!\r\n";
}

char * Msg2(void)
{
return "Less than 0!\r\n";
}

void PrintStr(char *(* Fun)(void))
{
puts(Fun());
}

int Sum(int a, int b)
{
return a + b;
}

char *(* Run(int a, int b, int (* SumFun)(int, int)))(void)
{
if(SumFun(a, b) >= 0)
return Msg1;
else
return Msg2;
}

int main()
{
PrintStr(Run(1,2,Sum));
PrintStr(Run(-1,-2,Sum));

return 0;
}

使用typedef的版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>

// Typedef
typedef int (* MySumFun)(int, int);
typedef char * (* MyCharFun)(void);

// Function declaration
void PrintStr(MyCharFun);
MyCharFun Run(int, int, MySumFun);

char * Msg1(void)
{
return "Great than 0!\r\n";
}

char * Msg2(void)
{
return "Less than 0!\r\n";
}

void PrintStr(MyCharFun Fun)
{
puts(Fun());
}

int Sum(int a, int b)
{
return a + b;
}

MyCharFun Run(int a, int b, MySumFun Fun)
{
if(Fun(a, b) >= 0)
return Msg1;
else
return Msg2;
}

int main()
{
PrintStr(Run(1,2,Sum));
PrintStr(Run(-1,-2,Sum));

return 0;
}

程序运行输出结果均为:

1
2
3
4
Great than 0!

Less than 0!

使用typedef的版本明显可读性要好得多。

文章目录