成员函数指针不是普通函数指针,不能直接转void*;其底层是多字段结构体(如{func_ptr, adjust_this_offset}),含this偏移或虚表索引,sizeof值因abi而异(4/8/16字节),强转会导致编译失败或崩溃。

成员函数指针不是普通函数指针,不能直接转 void*
这是最常踩的坑:试图用 reinterpret_cast<void>(&MyClass::func)</void> 获取“真实地址”,结果编译失败或运行时崩溃。C++ 标准明确禁止将成员函数指针隐式或直接转为对象指针类型。原因在于,非静态成员函数指针在多数 ABI(如 Itanium C++ ABI、MSVC)中实际是多字段结构体——可能含 this 偏移、虚表索引、甚至 thunk 地址,而非单个内存地址。
实操建议:
- 别尝试强转;
sizeof(&MyClass::func)在不同编译器下可能是 4、8 或 16 字节,印证它不是裸指针 - 若仅需“调用”,老实用
(obj.*ptr)()或(ptr_obj->*ptr)()语法 - 调试时想看底层布局?可用
std::memcpy拷贝到字节数组再逐字节观察(仅限调试,不可跨平台依赖)
MSVC 下用 __identifier 和内联汇编(x86)窥探 this 调度逻辑
仅适用于 MSVC x86 Debug 模式(x64 禁用内联汇编),且必须关闭优化(/Od)。此时某些简单非虚成员函数可能被编译为“带固定 this 偏移的裸函数”,可通过内联汇编读取当前 ecx(this 指针寄存器)验证调度机制。
示例(仅演示原理,不推荐生产使用):
void MyClass::func() {
int this_addr;
__asm {
mov this_addr, ecx
}
// 此时 this_addr 就是调用者的实际地址
}
注意:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 虚函数、多重继承、虚继承场景下,
ecx可能被 runtime 动态修正,该技巧立即失效 - Clang/GCC 不支持此内联语法;x64 下 MSVC 用
rcx但无内联汇编支持,需改用__readgsqword等间接方式,复杂度陡增
Itanium ABI 下解析 __func_ptr 结构体(GCC/Clang/Linux)
在 Linux 上用 GCC 编译时,成员函数指针底层是 struct { void *ptr; ptrdiff_t adj; }(见 abi.h),其中 ptr 是函数入口或 thunk 地址,adj 是 this 指针调整偏移(用于多重继承)。
安全提取函数地址的方法(仅限同 ABI 且非虚函数):
struct MemberFuncRep {
void* ptr;
ptrdiff_t adj;
};
auto rep = *reinterpret_cast<memberfuncrep>(&MyClass::func);
if (rep.adj == 0) {
// 此时 rep.ptr 可能是真实函数地址(非虚、单继承)
printf("Raw func addr: %p\n", rep.ptr);
}</memberfuncrep>
但必须注意:
- 虚函数的
ptr指向的是 vtable 中的 slot,不是函数本身;直接跳过去会 crash -
adj != 0表示 this 需偏移,此时即使拿到ptr,也不能脱离对象上下文单独调用 - 该结构体未标准化,不同 GCC 版本或
-fabi-version设置可能改变布局
真正需要“地址”的场景:Frida/Hooking/逆向,应绕过 C++ 抽象层
如果你目标是动态 Hook 成员函数(比如游戏外挂、调试器插件),不要从 C++ 源码里取 &MyClass::func——它没意义。应该:
- 用
objdump -t或readelf -s查符号表,找_ZN7MyClass4funcEv这类 mangled 名对应的真实地址 - 对虚函数,先定位对象的 vtable(通过对象首地址 + 0),再按虚函数序号读取 vtable[2] 得到实际函数地址
- 用
gdb的info symbol &MyClass::func只能告诉你“符号未解析”,因为 GDB 也受 C++ ABI 限制
ABI 差异和虚函数调度才是真正的门槛,写死地址或硬解构成员指针,在换编译器、升版本、加优化后大概率失效。与其纠结“怎么取地址”,不如确认你真正要 hook 的是不是那个最终被调用的物理函数——那通常得从二进制符号或运行时 vtable 入手。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










