函数指针声明关键在括号位置:int (func_ptr)(int) 正确,int func_ptr(int) 错误;星号须与标识符同括,否则被解析为函数声明;类型匹配需严格,包括参数、返回值、const/volatile及调用约定。

函数指针声明语法容易写反
函数指针声明最常错在括号位置——int (*func_ptr)(int) 是对的,int *func_ptr(int) 就变成函数声明了(返回 int* 的函数)。关键在于:星号必须和标识符一起被括号包住,否则优先级被参数列表拉走。
记住口诀:“先看变量名,再往外读”。(*func_ptr) 表示 func_ptr 是个指针,(*func_ptr)(int) 表示它指向一个接受 int、返回 int 的函数。
- 返回 void、参数为 double 和 const char* 的函数指针:
void (*handler)(double, const char*) - 指向成员函数的指针更复杂,需带类名:
void (MyClass::*method_ptr)() const - 用
typedef或using可提升可读性:using FuncPtr = int(*)(int);
初始化和赋值要确保类型严格匹配
函数名在多数上下文中会自动退化为函数指针,但类型必须完全一致:参数个数、类型、const/volatile 限定符、调用约定(如 __stdcall)都不能差。C++ 不做隐式转换。
- 正确:
int foo(int x) { return x; } int (*p)(int) = foo; - 错误:
int bar(long x) { return x; } p = bar;—— 即使 long 和 int 在当前平台等宽,类型不匹配仍编译失败 - 注意重载函数:直接写函数名会触发歧义错误,必须用
&foo显式取地址,并配合静态类型上下文
调用函数指针时括号不能省略
(*p)(42) 和 p(42) 都合法,但后者依赖编译器支持隐式解引用(C++11 起允许),前者更清晰、更接近语义本质。尤其在模板或复杂表达式中,显式 * 能避免歧义。
立即学习“C++免费学习笔记(深入)”;
- 如果 p 是
int (*p)(int),p(42)看起来像函数调用,实则是编译器“帮忙”加了* - 若 p 是
int (*p[10])(int)(函数指针数组),则必须写(*p[5])(42),p[5](42)才是标准写法 - 与 lambda 或 std::function 混用时,统一用
p(arg)更简洁,但底层仍是函数指针调用
函数指针不能直接指向 lambda(除非无捕获)
带捕获的 lambda 有闭包对象,不是普通函数,无法转成函数指针;无捕获 lambda 可隐式转换为对应签名的函数指针,但这是单向转换,且只在定义时发生。
- 可行:
auto f = [](int x) { return x + 1; }; int (*fp)(int) = f; - 不可行:
int y = 1; auto g = [y](int x) { return x + y; }; int (*gp)(int) = g;—— 编译错误 - 别试图对 lambda 取地址:
&f得到的是闭包类型的地址,不是函数指针
真正需要运行时切换逻辑时,优先考虑 std::function;只有对接 C API 或追求零开销时,才坚持用原生函数指针。


















