共有回帖数 0 个
-
在C++吧看到这样的问题, 以前没引起多大注意, 但细看之下, 猫腻不少.....
首先看看如下C++代码(所有测试在VC6.0下进行):
#includeiostream
int main(){
const int i = 1;
int b;
*(int*)&i = 4;
b = 4 + 1;
std::cout "i = " i std::endl;
return 0;
}
依常理看运行结果应该是4,但它确是1!
有几种直接看似合理的解释:
1. *(int*)&i = 4;没有被执行,或者编译器做了手脚,阻止了i的修改;
2. i被移入寄存器,cout入栈参数i被某个寄存器代替,比如push ebx;
3. 所有使用i的地方,i的值被立即数代替,cout压入的实则为1,push 1;
为了证明某个解释的正确,我们最好看看反汇编代码:
3: int main(){
00401570 push ebp
00401571 mov ebp,esp
00401573 sub esp,48h
00401576 push ebx
00401577 push esi
00401578 push edi
00401579 lea edi,[ebp-48h]
0040157C mov ecx,12h
00401581 mov eax,0CCCCCCCCh
00401586 rep stos dword ptr [edi]
4:
5: const int i = 1;
00401588 mov dword ptr [ebp-4],1
6: int b;
7: *(int*)&i = 4;
0040158F mov dword ptr [ebp-4],4
8:
9: b = 4 + 1;
00401596 mov dword ptr [ebp-8],5
10: std::cout "i = " i std::endl;
0040159D push offset @ILT+195(std::endl) (004010c8)
004015A2 push 1
004015A4 push offset string "i = " (0046c01c)
004015A9 push offset std::cout (004777e0)
004015AE call @ILT+640(std::operator) (00401285)
004015B3 add esp,8
004015B6 mov ecx,eax
004015B8 call @ILT+250(std::basic_ostreamchar,std::char_traitschar ::operator) (004010ff)
004015BD mov ecx,eax
004015BF call @ILT+475(std::basic_ostreamchar,std::char_traitschar ::operator) (004011e0)
11: return 0;
004015C4 xor eax,eax
12: }
很显然1,2被淘汰了,那么3呢,只说对了一半,并不完全正确,
7: *(int*)&i = 4;
0040158F mov dword ptr [ebp-4],4
在赋值表达式中,i被确确实实的修改了,但在
9: b = 4 + 1;
00401596 mov dword ptr [ebp-8],5
中,i被立即数1代替了!
再来看cout的参数入栈,
0040159D push offset @ILT+195(std::endl) (004010c8)
004015A2 push 1
004015A4 push offset string "i = " (0046c01c)
004015A9 push offset std::cout (004777e0)
里面连个i的影子都没有,那么i呢?
004015A2 push 1,
和9: b = 4 + 1;的情况一样,
i被立即数1代替了.....哈哈哈哈哈哈.........
总结: 在C++中,对i的赋值语句中,i在内存的值会被改变,
但在运算表达式和参数入栈中,编译器会用对应的立即数代替它,
至于返回i会发生什么,有兴趣的可以自己试试,嘿嘿!
好了,到此问题绝不能结束,因为这是C语言吧- -.........
同样的代码,改成C语言:
#include stdio.h
int main(){
const int i = 1;
int b;
*(int*)&i = 4;
b = 4 + 1;
printf("i = %dn", i);
return 0;
}
输出多少?认为是1的就大错特错了,结果是4!
哈哈,晕吧,看反汇编码:
3: int main(){
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,48h
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-48h]
0040101C mov ecx,12h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
4:
5: const int i = 1;
00401028 mov dword ptr [ebp-4],1
6: int b;
7: *(int*)&i = 4;
0040102F mov dword ptr [ebp-4],4
8:
9: b = 4 + 1;
00401036 mov dword ptr [ebp-8],5
10: printf("i = %dn", i);
0040103D mov eax,dword ptr [ebp-4]
00401040 push eax
00401041 push offset string "i = %dn" (0042001c)
00401046 call printf (00401080)
0040104B add esp,8
11: return 0;
0040104E xor eax,eax
12: }
对于赋值和运算表达式,编译器的处理一样,但参数入栈:
0040103D mov eax, dword ptr[ebp-4]
00401040 push eax
00401041 push offset string "i = %dn" (0042001c)
这回压的是正经的i(dword ptr[ebp-4]),
因为i在前面被改变了,所以结果为4!
总结总结: 对于C语言,编译器对赋值和运算表达式的处理同C++,
但被压入的参数i,为其自身,并不是立即数!
对于返回值,自己去试...
最后还要唠叨两句,这些测试都是在6.0中进行的,不保证其他编译器
的处理结果,更不保证优化后的结果,发贴目的,只是为了各吧友在
遇到类似问题后,能够参考分析,不至晕头转向,无从下手...
最后的最后,对于压栈规则,标准C/C++有相关规定么???
楼主 2016-02-05 18:50 回复
Copyright © 2010~2015 直线网 版权所有,All Rights Reserved.沪ICP备10039589号
意见反馈 |
关于直线 |
版权声明 |
会员须知