C++的this指针在成员函数被调用时是如何传入的? (Calling Convention)

2次阅读

this是编译器隐式传递的首个参数,x86 windows下通过ecx寄存器传递,linux/macos下按system v abi作为第1参数入rdi,x64 windows下入rcx;operator new为静态函数,无this。

C++的this指针在成员函数被调用时是如何传入的? (Calling Convention)

成员函数调用时,this 是怎么进来的?

它不是靠你写出来的参数,而是编译器悄悄塞进第一个隐式参数位置的。不同平台和 ABI 下,传参方式略有差异,但核心逻辑一致:就像 C 函数调用一样,this 被当作一个额外的指针参数,在调用前就准备好,走的是和普通参数相同的寄存器或路径。

thiscall 在 x86 Windows 上到底干了什么?

这是微软 MSVC 在 32 位 x86 下对非静态成员函数的默认调用约定。它的关键行为是:thisECX 寄存器,其余参数从右往左压栈。

  • 如果你手写汇编或逆向看反汇编,会发现 mov ecx, [some_obj] 总在 call 前出现
  • 返回值、栈平衡规则和 __cdecl 类似(调用者清栈),但 this 不占栈空间
  • 注意:MSVC 在 x64 下统一用 __fastcall 变体(thisRCX),thiscall 已被弃用,仅保留在 x86 文档里
  • g++/clang 在 x86 Linux 下不认 thiscall,它们用的是 System V ABI:所有参数(含 this)都按规则进寄存器或栈,this 就是第一个参数

为什么重载 operator new 时不能直接访问 this

因为 operator new 是静态成员函数,它在对象内存分配完成前就被调用 —— 此时对象还没构造,this 根本不存在。

  • 错误写法:void* operator new(size_t s) { return this->malloc(s); } → 编译不过,this 未定义
  • 正确做法:它只能访问全局 malloc、静态变量或传入的 s,返回的是原始内存地址
  • 真正拿到 this 是在后续的构造函数里,此时内存已分配,对象生命周期才开始

内联汇编或 ABI 兼容时,this 的位置容易搞错吗?

非常容易。尤其当你手动写汇编包装成员函数,或跨语言绑定(比如用 rustc++ 成员函数)时,漏掉 this 或放错位置会导致段错误或随机崩溃。

立即学习C++免费学习笔记(深入)”;

  • x86-64 System V(Linux/macOS):this 是第 1 个参数,进 RDIint a, int b 分别进 RSIRDX
  • x86-64 microsoft(Windows):this 是第 1 个参数,进 RCX;其余依次是 RDXR8R9
  • 如果用 extern "C" 暴露成员函数,必须自己把 this 当成显式参数传进去,否则 ABI 不匹配
  • 调试时可查 objdump -d 或用 gdbcall 前寄存器状态,确认 RCX/RDI 是否已被设为对象地址

最常被忽略的一点:成员函数指针不是普通函数指针,它可能包含偏移、调整值甚至虚表索引 —— 所以你不能简单假设 this 就是“第一个参数”,尤其在涉及多重继承或虚继承时,编译器会在调用前悄悄修正它。

text=ZqhQzanResources