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++不那么好调咧?