从汇编看c++ static函数

cpp代码

$ cat main.cpp
#include <stdio.h>
#include <stdlib.h>

class CAAA {
public:
        int mX;
        int fBBBB(int x, int y) {return x - y + mX;}
        static int fCCCC(int x, int y) {return x + y;}
};


int main() {
        CAAA a;
        int var1 = CAAA::fCCCC(1, 4);
        int var2 = a.fBBBB(2, 6);

        printf("%d\r\n", var1);
        printf("%d\r\n", var2);
        return 0;
}

汇编及运行期栈

int main() {
 80484c4:       55                      push   %ebp          #保存前栈帧
 80484c5:       89 e5                   mov    %esp,%ebp     #保存当前栈帧
 80484c7:       83 e4 f0                and    $0xfffffff0,%esp #esp向下对齐到16
 80484ca:       83 ec 20                sub    $0x20,%esp       #esp-=32
        CAAA a;
        int var1 = CAAA::fCCCC(1, 4);
 80484cd:       c7 44 24 04 04 00 00    movl   $0x4,0x4(%esp) #*(esp+4)=4 通过栈传第2参
 80484d4:       00
 80484d5:       c7 04 24 01 00 00 00    movl   $0x1,(%esp)    #*esp=1 通过栈传第1参
         
        (gdb) x/2x $esp
        0xbffff720:     0x00000001      0x00000004
 
 80484dc:       e8 68 00 00 00          call   8048549 <_ZN4CAAA5fCCCCEii>
 80484e1:       89 44 24 18             mov    %eax,0x18(%esp)
 
 
        int var2 = a.fBBBB(2, 6);
 80484e5:       c7 44 24 08 06 00 00    movl   $0x6,0x8(%esp) #*(esp+8)=6 通过栈传第3参
 80484ec:       00
 80484ed:       c7 44 24 04 02 00 00    movl   $0x2,0x4(%esp) #*(esp*4)=2 通过栈传第2参 
 80484f4:       00
 80484f5:       8d 44 24 1c             lea    0x1c(%esp),%eax #令eax=esp+0x1C
 80484f9:       89 04 24                mov    %eax,(%esp)     #*esp = eax = esp+0x1C,通过栈传第1参,也就是对象a的地址,即a.this
        (gdb) x/3x $esp
        0xbffff720:     0xbffff73c      0x00000002      0x00000006
        (gdb) p sizeof(a)
        $1 = 4
        (gdb) p &a
        $2 = (CAAA *) 0xbffff73c
        (gdb) p &a.mX
        $3 = (int *) 0xbffff73c


 80484fc:       e8 33 00 00 00          call   8048534 <_ZN4CAAA5fBBBBEii>
 8048501:       89 44 24 14             mov    %eax,0x14(%esp)

        printf("%d\r\n", var1);
 8048505:       8b 44 24 18             mov    0x18(%esp),%eax
 8048509:       89 44 24 04             mov    %eax,0x4(%esp)
 804850d:       c7 04 24 20 86 04 08    movl   $0x8048620,(%esp)
 8048514:       e8 d7 fe ff ff          call   80483f0 <printf@plt>
        printf("%d\r\n", var2);
 8048519:       8b 44 24 14             mov    0x14(%esp),%eax
 804851d:       89 44 24 04             mov    %eax,0x4(%esp)
 8048521:       c7 04 24 20 86 04 08    movl   $0x8048620,(%esp)
 8048528:       e8 c3 fe ff ff          call   80483f0 <printf@plt>
        return 0;
 804852d:       b8 00 00 00 00          mov    $0x0,%eax
}
 8048532:       c9                      leave
 8048533:       c3                      ret
 
 
 
 
        int fBBBB(int x, int y) {return x - y + mX;} #看汇编可知有非静态方法参数中必有this参数
 8048534:       55                      push   %ebp
 8048535:       89 e5                   mov    %esp,%ebp
    此时的运行期的栈长这个样子
                +---------------------+
                | ...........         |
                |第3参:值为6           | +16
                |第2参:值为2           | +12
                |a.this 0xbffff73c    | +8
                |return addr:0x8048501| +4
      ebp,esp-> |old ebp              | +0
                |                     |
 
 8048537:       8b 45 10                mov    0x10(%ebp),%eax  #eax=*(ebp+16) 取出第3参y到eax,也就是6
 804853a:       8b 55 0c                mov    0xc(%ebp),%edx   #edx=*(ebp+12) 取出第2参x到edx
 804853d:       29 c2                   sub    %eax,%edx        #edx-=eax 计算x-y存到edx
 804853f:       8b 45 08                mov    0x8(%ebp),%eax   #eax=*(ebp+8) 取出a.this放到eax
 8048542:       8b 00                   mov    (%eax),%eax      #eax = *(int*)a.this 因为mX是首成员*(int*)a.this就是mX
 8048544:       8d 04 02                lea    (%edx,%eax,1),%eax #eax = edx+eax
 8048547:       5d                      pop    %ebp
 8048548:       c3                      ret

08048549 <_ZN4CAAA5fCCCCEii>:
        static int fCCCC(int x, int y) {return x + y;} #看汇编可知有静态方法参数中必无this参数
 8048549:       55                      push   %ebp
 804854a:       89 e5                   mov    %esp,%ebp
    此时的运行期的栈长这个样子
                +---------------------+
                | ...........         |
                |第2参:值为4           | +12
                |第1参:值为1           | +8
                |return addr:0x80484e1| +4
      ebp,esp-> |old ebp              | +0
                |                     |
 804854c:       8b 45 0c                mov    0xc(%ebp),%eax  #eax=*(ebp+12) 取出第2参y到eax
 804854f:       8b 55 08                mov    0x8(%ebp),%edx  #edx=*(ebp+8) 取出第1参y到edx
 8048552:       8d 04 02                lea    (%edx,%eax,1),%eax #eax=edx+eax=x+y
 8048555:       5d                      pop    %ebp
 8048556:       c3                      ret

结论

 1.类的static函数调用传参时,一定是不传递this的.相反普通的类函数必隐式传递this在第一个参数位上.

 2.在没有virtual函数重写或如题中不需要虚函数表的时候,类的成员函数地址可不在类内部反映(可能依赖于编译器的实现)

 3.所谓类的成员函数(不管是否是static),其实现和普通的c函数没啥两样

    哪为啥在c中调用c++不那么好调咧?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值