从汇编层面理解C++ this指针

c++中,调用对象的非静态成员函数过程中,编译器会自动添加this指针作为第一个参数。我们从汇编层面看看this指针是如何传进来的。

使用如下简单的程序来演示:

cpp 复制代码
class A
{
private:
  int a[100];
  int b;
public:
  void SetB(int b)
  { this->b = b;}
  int GetB() { return this->b;}
};


int main()
{
  A oa ;
  oa.SetB(0x888);

  int b = oa.GetB();
  return 0;
}

编译后反汇编A::SetB汇编如下:

shell 复制代码
0000000000400536 <_ZN1A4SetBEi>:
  400536:       55                      push   %rbp
  400537:       48 89 e5                mov    %rsp,%rbp
  40053a:       48 89 7d f8             mov    %rdi,-0x8(%rbp)
  40053e:       89 75 f4                mov    %esi,-0xc(%rbp)
  400541:       48 8b 45 f8             mov    -0x8(%rbp),%rax
  400545:       8b 55 f4                mov    -0xc(%rbp),%edx
  400548:       89 90 90 01 00 00       mov    %edx,0x190(%rax)
  40054e:       5d                      pop    %rbp
  40054f:       c3                      retq

可以看到,寄存器rdiesi分别表示第一个参数this和第二个参数int b

最后通过mov %edx,0x190(%rax) 指令实现this->b = b;

类内变量b相对于对象起始地址this的偏移是0x190,可以通过gdb验证偏移量:

shell 复制代码
(gdb) p &(((A*)0)->b)
$1 = (int *) 0x190
(gdb)

可以看到, 编译器确实将this指针作为第一个参数传到非静态成员函数中了。

看了成员函数的汇编, 再看看main函数中是如何调用的。

main函数的汇编如下:

shell 复制代码
00000000004004fd <main>:
  4004fd:       55                      push   %rbp
  4004fe:       48 89 e5                mov    %rsp,%rbp
  400501:       48 81 ec a0 01 00 00    sub    $0x1a0,%rsp
  400508:       48 8d 85 60 fe ff ff    lea    -0x1a0(%rbp),%rax
  40050f:       be 88 08 00 00          mov    $0x888,%esi
  400514:       48 89 c7                mov    %rax,%rdi
  400517:       e8 1a 00 00 00          callq  400536 <_ZN1A4SetBEi>
  40051c:       48 8d 85 60 fe ff ff    lea    -0x1a0(%rbp),%rax
  400523:       48 89 c7                mov    %rax,%rdi
  400526:       e8 25 00 00 00          callq  400550 <_ZN1A4GetBEv>
  40052b:       89 45 fc                mov    %eax,-0x4(%rbp)
  40052e:       b8 00 00 00 00          mov    $0x0,%eax
  400533:       c9                      leaveq
  400534:       c3                      retq
  400535:       90                      nop

main函数中定义了局部变量oa,在栈上申请内存。

第三条指令sub $0x1a0,%rsp, 表示在栈上申请了0x1a0个字节,此时%rsp=-0x1a0(%rbp)-0x1a0(%rbp)其实就是栈顶,也是对象oa的地址,即this指针。

第四条指令lea -0x1a0(%rbp),%rax执行后,this指针保存在%rax中。

第6/7条指令,分别将this指针及变量int b(0X888)放入rdirsi表示第一/二个参数, 然后调用A::SetB

上述程序,对象在栈上。 如果对象在堆上的情况,即通过new申请的对象,可能会有所不同。

相关推荐
SilentSlot6 小时前
【C/C++】手写 DPDK 协议栈(十二):TCP 并发与自实现 epoll 的就绪事件分发
c语言·c++·tcp/ip
雨落在了我的手上6 小时前
Java数据结构(九):栈和队列
java·开发语言·数据结构
SilentSlot6 小时前
【C/C++】手写 DPDK 协议栈(六):TCP 三次握手、状态机与数据回显
c语言·c++·tcp/ip
j7~6 小时前
【C语言】《C语言自定义类型(结构体+联合体+枚举类型)》--详解
c语言·开发语言·深度学习·结构体·位段·联合体·枚举类型
乱七八糟的屋子6 小时前
AMQP C++ 超详细实战教程(amqp-cpp 开源库从零入门到生产落地)
c++·rabbitmq·任务队列·amqp·流量削峰·c++服务端异步解耦·分布式消息通信
Escalating_xu6 小时前
C++11 彻底吃透 emplace_back 与 push_back(最全闭环:左右值|深浅拷贝|移动构造|万能引用|完美转发)
开发语言·c++
天天进步20156 小时前
Python全栈项目--基于机器学习的金融风险评估系统
开发语言·python·机器学习
啦啦啦啦啦zzzz6 小时前
oat++框架应用之do、dao、service
服务器·c++·mysql·oatpp
皓月斯语7 小时前
B3865 [GESP202309 二级] 小杨的 X 字矩阵 题解
开发语言·c++·矩阵·题解
paeamecium8 小时前
【PAT甲级真题】- Rational Sum (20)
数据结构·c++·python·算法·pat考试·pat