函数指针声明需完整指定返回类型、参数列表和*位置,如int (*p)(int, int) = &add;;获取地址用&func更安全,调用可用p(args...)或(*p)(args...)。

函数指针怎么声明和获取地址
C++ 中普通函数(非成员函数、非模板实例化前的函数)的地址可以直接用取址符 & 获取,但类型必须匹配。声明函数指针时,语法容易出错:返回类型、参数列表、* 位置缺一不可。
-
int func(int)对应的函数指针类型是int ()(int),不是int ()或int (*)()(后者参数不明确,可能被当作 C 风格可变参) - 获取地址时,
&func和func在大多数上下文中等价(函数名会自动退化为指针),但显式写&func更清晰、更安全,尤其在模板或重载场景下可避免歧义 - 成员函数不能直接用
&得到“普通指针”,必须用指向成员函数的指针类型ReturnType (Class::*)(Args...),且调用时需绑定对象
怎么用函数指针安全调用
调用函数指针前,务必确保它非空,且类型与实际目标函数完全一致(参数个数、cv 限定、调用约定)。否则行为未定义,常见现象是栈被破坏、程序崩溃或静默错误。
- 调用方式统一为
(*ptr)(args...)或更简洁的ptr(args...)(两者等价,编译器自动解引用) - 若函数有
stdcall或cdecl等调用约定(Windows API 常见),函数指针声明中必须显式标注,否则链接或调用时可能栈不平衡 - 示例:
int add(int a, int b) { return a + b; } int (*p)(int, int) = &add; int r = p(3, 4); // 正确,等价于 (*p)(3, 4)
lambda 和 std::function 怎么处理地址问题
捕获为空的 lambda([ ](){} )可以隐式转换为对应签名的函数指针,但仅限无捕获情况;一旦捕获变量,就无法转成函数指针,只能用 std::function 包装。
-
auto f = []{ return 42; };→ 可赋给int(*)();但int x = 0; auto g = [x] { return x; };→ 不行 -
std::function是类型擦除容器,不保存“地址”概念,底层可能存函数指针、functor 或 lambda,调用有轻微开销(虚函数或间接跳转) - 不要试图对
std::function对象取地址来获得其封装函数的原始地址——它根本没提供这个接口
容易忽略的坑:模板函数和重载函数的地址
模板函数名本身不是函数,只有实例化后才有地址;重载函数名则存在二义性,编译器无法凭空决定选哪个。
-
&std::max编译失败,因为std::max是重载集;必须强制指定类型:int(*)(int,int)(&std::max)或用 static_cast - 函数模板如
template,要取地址必须先实例化:T identity(T x) { return x; } &identity,&identity无效 - 类内定义的 inline 函数地址在不同编译单元可能相同也可能不同(ODR 保证下通常一致),但不要依赖地址相等来判断是否同一函数
函数地址不是万能句柄,它不携带调试信息、不支持反射、不能跨 ABI 安全传递;真正需要动态分发逻辑时,优先考虑虚函数、策略模式或 std::function,而不是裸指针。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











