钱能c++以 局部函数 引出 函数调用机制中疑惑解答

钱能c++ 局部函数

 

#include<iostream.h>
int func1();
int func2();
void main()
{
func1();
cout<<func2()<<endl;
}
int func1()
{
int n=12345;
return n;
}
int func2()
{
int m;
return m;
}

会输出什么呢?
钱能的书中讲述输出 12345。

测试结果

VC6:

Debug:
-858993460
Press any key to continue

Release:
4199033
Press any key to continue

 

WHY?


C++已有很多经典著作。

1.如果没有优化
func1()返回以后,是有12345在栈里。这时候还没有覆盖。
但是接下来调用fun2(),会有一系列的PUSH,前面的数据已经覆盖。
返回值完全取决于eax赋值前的那个PUSH。

因为没有初始化,所以取决于编译器怎么编译。
VC6是采用ecx的值给它初始化。
如下这样的一种编译, 打印值是ecx的值。

// fun1()
PUSH EBP
MOV EBP, ESP
PUSH ECX
MOV DWORD PTR [EBP-4], 3039
MOV EAX, DWORD PTR [EBP-4]
MOV ESP, EBP
POP EBP
RETN

int func1()
{
int n=12345;
return n;
}

// fun2()
PUSH EBP
MOV EBP, ESP
PUSH ECX
MOV EAX, DWORD PTR [EBP-4] //EAX的值与刚才ECX的值一致
MOV ESP, EBP
POP EBP
RETN

int func2()
{
int m;
return m;
}

2.如果优化
编译器会优化这个函数,直接mov 到eax返回,根本不会有12345在栈里。
MOV EAX,3039
RETN

int func1()
{
int n=12345;
return n;
}


// 后面还是取决于push
// 这时候 EAX取了栈里的值,自然也不是12345
可以这样:
PUSH ECX
MOV EAX, DWORD PTR [ESP]
POP ECX
RETN

也可以这样优化
PUSH ECX
MOV EAX, DWORD PTR [ESP]
ADD ESP, 4
RETN

或者这样
SUB ESP,4
MOV EAX, DWORD PTR [ESP]
ADD ESP, 4
RETN

甚至这样:
MOV EAX, DWORD PTR [ESP - 4]
RETN

int func2()
{
int m;
return m;
}

 

的确是编译器优化导致的,
早期的编译器,都是把局部变量都放在堆栈中了,对esp指针的移动也是通过sub指令来操作的,因此就一定会输出12345
由于对内存操作的缓慢,现在编译器会把一些局部变量放到寄存器中,就会导致这种现象
还有就是移动esp指针的问题,现在对函数内部只有一两个变量的情况,也不用sub指令了,而是直接用push reg指令了,这样可以减少代码长度,sub指令至少要3个字节,而push reg只需一个字节,不过这种替换虽然可以减小程序体积,但是降低了程序效率,push reg指令要直接操作内存,慢,花费时钟周期多...

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

do2jiang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值