函數指針:函數的入口地址
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內核實現中大量使用了函數指針。待補充…