函数指针:函数的入口地址
C程序变量驻留在程序内存空间的某个地址,它所在的地方取决于变量类型(自动变量、静态变量或全局变量等)。我们可以很容易打印变量的地址,如下所示:
#include
int main(void)
{
int i = 3;
printf("i resides at %p\n", &i); //i resides at 0xbfef6c44
return 0;
}
在程序中,操作符&作用于变量i,要求生成i的地址,而格式化标识符%p指定输出内存地址。上述程序的可能输出如下:
i resides at 0xbfef6c44
同变量一样,我们也可以打印函数的地址。下面这段代码说明了这一点:
#include
void func(void);
int main(void)
{
int i = 3;
printf("i resides at %p\n", &i); // i resides at 0xbfe2f6f4
printf("func() resides at %p\n", &func); // func() resides at 0x80483fa
// printf("func() resides at %p\n", func); // func() resides at 0x80483fa
printf("main() resides at %p\n", &main); // main() resides at 0x8048368
// printf("main() resides at %p\n", main); // main() resides at 0x8048368
return 0;
}
void func(void)
{
printf("Hello, world\n");
}
对应的输出如下:
i resides at 0xbfe2f6f4
func() resides at 0x80483fa
main() resides at 0x8048368
实际上,函数也驻留在程序的内存空间中。地址操作符&也可以作用于函数,从而生成函数所在的地址。
如何声明函数指针
在C语言中,所有变量都需要声明和定义,函数指针也不例外。
变量和指针的声明及定义如下:
int i;
int *int_ptr = &i;
很自然会联想到:
int f(int arg);
int *func_ptr(int arg) = &f;
实际上,由于根据运算符优先级规则,括号的优先级要比指针高,因此这种形式定义了一个指针函数,也就是一个返回指向整型数的指针的函数。
函数指针的正确定义为:
int f(int arg);
int (*func_ptr)(int arg) = &f;
需要强调的是,函数指针和它所指向的函数应该是兼容的。下例给出了一些对函数及函数指针的错误赋值:
int func(int arg)
{
return 0;
}
int *func_ptr1(int arg);
int (*func_ptr2)(int arg);
int (*func_ptr3)(void);
double (*func_ptr4)(int arg);
int main(void)
{
// func_ptr1 = &func; //error: invalid lvalue in assignment
func_ptr2 = &func; //pass
// func_ptr3 = &func; //warning: assignment from incompatible pointer type
// func_ptr4 = &func; //warning: assignment from incompatible pointer type
}
其中,只有第二个赋值是正确的。在示例一中,func_ptr1并不是函数指针,而是一个指向指针的函数。在示例三中,func_ptr3只能指向没有参数的函数,而函数func带有一个整型参数。而示例四中,func_ptr4只能指向返回double类型的函数,而函数func返回的是int类型。
如何获得函数的地址
有两种方式获取函数的地址。假设funcptr是一个函数指针。如果我们将它指向一个兼容函数func()。
第一种方法使用隐式指针转换(implicit conversion to pointer):
funcptr = func;
第二种方法使用显式指针转换(explicit conversion to pointer):
funcptr = &func;
这两种方法都是可行的。实际上,如果在程序中有第一种形式的语句,编译器会把它自动转换为第二种方式。
使用函数指针调用函数
象获取函数的地址一样,通过函数指针调用函数的方法也有两种:
第一种是使用显式指针(explicit dereference of the pointer),如下:
extern void func(int x, int y);
void (*func_ptr)(int x, int y) = func;
(*funcptr)(3, 2);
第二种称为隐式指针(implicit dereference of the pointer)。
extern void func(int x, int y):
void (* func_ptr)(int x, int y) = func;
funcptr(3, 2);
函数指针的应用
在Linux内核实现中大量使用了函数指针。待补充…