今日阅读《STL源码剖析》至2.2节P57时,遇到令我感到困惑的一段代码,见下。
static void(* set_malloc_handler(void (*f)()))(){
void (*old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f;
return (old);
}
简单讲一下这段代码的作用:其中 是一个函数指针,声明如下:
static void (* __malloc_alloc_oom_handler)();
用于指向处理出现 时调用的处理函数。这段函数接收一个指向自定义的 处理函数的函数指针 ,在函数内部先保存 记录的旧值 然后将其赋值为 。最后将旧值 返回。
理解函数的逻辑并不困难,但是函数的声明形式有待理解。什么是函数指针呢?下面讲解。
函数指针
请注意区分函数指针和指针函数。我们知道,在c++中,存在包括基本数据类型在内的数据类型,事实上,函数同样存在不同的类型——函数的类型由其返回值以及形参决定,这两者称之为函数特征(符)。和其他数据类型可以通过指针进行访问一样,函数同样可以用特殊的指针进行间接的调用。相对于其他数据类型,指针指向的是其地址,而函数指针指向的是函数代码的地址。
函数指针的声明
函数指针的声明格式通常如下:
例如:
void (*func)(); // 声明一个**无返回值**且**参数列表为空**的函数指针
int (*func)(int, int); // 声明一个返回值类型为 int,参数列表类型均为 int 的函数指针
...
// 通过函数指针调用函数:
int a = (*func)(1,2);
// 或
int b = func(1, 2);
在理解上面这个问题之前,首先来看一个非常典型的例子:
(* (void (*)()) 0)(); //出自经典书籍《C Trap and Pitfalls》
如何理解?不妨逐层探之。首先 是一个无返回值且参数列表为空的函数指针类型,于是可知, 强制将 转化为函数指针,然后进行调用。
释解
有了上面函数指针的基础,我们便可以对问题进行解释了:
static void(* set_malloc_handler(void (*f)()))(){
void (*old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f;
return (old);
}
同样,由内而外逐层进行理解。首先 void (*f)() 是一个无返回值且参数列表为空的函数指针。既然如此,那么 set_malloc_handler(void (*f)()) 应该是一个函数,形参类型是一个函数指针 void (*f)()。
如果将 set_malloc_handler(void (*f)()) 视为一个整体 P,可以得到 void (* P)(),同样也是一个无返回值,参数列表为空的函数指针。然而注意到 set_malloc_handler(void (*f)()) 前是 ,说明函数 set_malloc_handler(void (*f)()) 返回一个指针。而这个指针也有自己的参数列表(为空),以及返回值类型为 void。于是可知 set_malloc_handler(void (*f)()) 的返回类型是无返回值,参数列表为空的函数指针。
事实上,上面的函数有更易读的等价写法:
typedef FuncType void (*)();
Functype set_malloc_handler(void (*f)()){
...;
}