函数声明
void func();/* 声明一个函数 */
• 格式: 返回值类型 函数名([形参列表]);
• 含义: 声明一个无返回值(void)、无参数的函数 func。
• 函数名: func是一个函数指示符(function designator,即函数名),它会自动转换为函数指针类型,指向函数的入口地址。
• 地址: func、&func、*func 在语义上都等价,表示函数的首地址。
函数指针声明
void (*init)();/* 声明一个函数指针 */
• 格式: 返回值类型 (*指针变量名) ([形参列表]);
• 含义: 声明一个函数指针 init,它可以指向一个返回值为 void、无参数的函数。
• 括号的必要性: (*init) 的括号不可省略,否则void *init() 会变成一个返回void*的函数声明,而不是函数指针。
函数指示符与函数指针的关系
• C语言: 函数指示符(上文func)不是左值也不是右值,但在表达式中会自动转换为函数指针类型的右值。
• C++: 函数指示符是左值,转换为右值的过程是左值到右值的转换。
• 赋值:可以用init = func;或init = &func;将函数地址赋给指针。
• 调用方式: 通过函数指针调用时,init() 和 (*init)() 等价,不需要显式解引用(*),因为编译器会自动处理。
类型匹配
• 函数指针的类型由 返回值类型 和 形参列表 共同决定。
示例
void (*init1)() 和 void (*init2)(void *) 是不同类型的函数指针。
混用可能引发警告(warning),甚至未定义行为(undefined behavior)。
示例解析
• 示例 1
void (*init)(); /* 声明一个函数指针 */
• 未初始化时,init的值未定义,可能指向随机地址。
• init = *init是未定义行为,因为init未初始化。
• &init 是 init 这个指针变量本身的地址。
• 示例 2
声明函数:
int abc(int a);//函数abc,返回类型int,形参int
int abcd(int *a);// 函数abc,返回类型int,形参int *
声明函数指针:
int (*init1)(int);// 函数指针init1,返回类型int,形参int
int (*init2)(int*);//函数指针init2,返回类型int,形参int *
赋值:
init1=abc;或者init1=&abc;
init2=abcd;或者init2=&abcd;
调用方式:
*init1()或者init1()
*init2()或者init2()
由于函数指针init1和init2的返回值类型格式相同,init2=abc或者init1=abcd ,形参类型不匹配,会有warning但可能可以正常使用。
类型转换与 void*
void*区别于void (*)(),void*是一个通用指针类型,不能直接用于函数指针
(void *)可以用于强制类型转换为空指针类型
比如指针函数void *func(); 表示返回值是指针类型
(void (*)(void *))是将某个值强制转换为一个函数指针类型,指向的函数接受void*参数。
typedef 使用
typedef void(*FunType)();/* 定义一种函数指针类型的格式,函数指针类型别名FunType*/
Funtype init;//等价于 void (*init)();
函数指针的用途
• 函数指针允许将函数作为参数传递,从而实现更高的灵活性。
• 常用于回调函数、动态函数调用(如函数表)。
示例
void say_hello() {
printf("Hello\n");
}
void call_func(void (*init)()) { /*void (*init)(); 声明参数名为init,类型是 void (*init)(),即一个指向无参数、返回值为 void 的函数的指针。*/
init(); /*表示通过这个函数指针调用它所指向的函数*/
}
int main() {
call_func(say_hello); //输出"Hello"
//call_func(say_hello) 将 say_hello 函数的地址传递给 call_func
//say_hello 是一个函数指示符(函数名),函数名本身就代表该函数的地址,可以直接传递给 call_func
//call_func 的参数f接收到 say_hello 的地址后,在函数中通过 init() 调用say_hello
return 0;
}
注意事项
• 未初始化的函数指针使用前必须赋值,否则会导致未定义行为。
• 函数指针调用时,参数类型和数量必须与声明一致。