现在的位置: 首页 > 综合 > 正文

C++ const const_cast 行为分析

2012年05月25日 ⁄ 综合 ⁄ 共 3706字 ⁄ 字号 评论关闭

  事情的起因呢,我就不说了,总之今天花了两个小时研究了一下C++中的const const_cast行为,发现与原先预想的很不一样...  

  先看一段代码:

  

const


#include
<stdio.h>

int main()
{
const int a=2;
const int * b=&a;
printf(
"%d, %d, %d, %d\n", a, *b, &a, b);
int * c=const_cast<int *>(b);
printf(
"%d, %d\n", *c, c);
*c=4;
printf(
"%d, %d, %d, %d, %d, %d\n", a, &a, *b, b, *c, c);
const int e=a;
printf(
"%d, %d, %d, %d\n", e, &e, &a, *(&a));
int d=(int)&a;
printf(
"%d, %d, %d, %d, %d\n", a, &a, d, &d, *(int *)d);
const int * f=&a;
printf(
"%d, %d\n", *f, f);
}

 

 

  过客们知道其中玄机的可以忽略本文,不知道的可以先想一想预想的结果...再运行一下...看一下实际的结果...

 

  大体的意思呢,就是我申明了一个int类型的const变量...

  然后呢用const_cast 将const属性去掉了,再去输出其值...看一下结果...预想的结果,凡是输出a的地方,应该都变成了4...

实际上...结果是这个样子的...

 

2, 2, 2423784, 2423784
2, 2423784
2, 2423784, 4, 2423784, 4, 2423784
2, 2423748, 2423784, 2
2, 2423784, 2423784, 2423736, 4
4, 2423784
请按任意键继续. . .

 

  很明显...凡是输出a的地方...都变成了2...(蓝色即为a的地址,红色为我幻想着为4实际上为2的a的值...)当然我不死心...这是在VS2010下的结果...放到RedHat GCC下编译运行...幻想着我找到了VC的bug了...发现结果...和VC是一样的...

 

  我迷失了...调试内存...发现a的那块地址...的的确确千真万确...变成了4...我怒了...

 

  翻开C++ Primer Plus(第五版中文版) 585页 里面在描述const_cast的一段代码的时候,这么描述:“... ...调用change()时,修改了pop1,但没有修改pop2(在使用的编译器生成pop2的一个临时拷贝,并将地址赋给pc,但正如前面指出的,C++标准指出,在这种情况下,上述行为时不确定的)。”

这么一句话的意思是?当试图强制转换一个const变量时,会生成一个副本,保留原来的值?实际情况貌似不是这样的...我在内存里可找不到那个副本...

 

  无奈之后,查看汇编后的代码...以下截取最重要的一部分(VC上编译开关加上/FAs,这么强大的功能...还有对应的注释语句)看完了...我豁然开朗...也顿时无奈了...

 

代码

; 5 : {

push ebp
mov ebp, esp
sub esp, 264 ; 00000108H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-264]
mov ecx, 66 ; 00000042H
mov eax, -858993460 ; ccccccccH
rep stosd

; 6 : const int a=2;

mov DWORD PTR _a$[ebp], 2

; 7 : const int * b=&a;

lea eax, DWORD PTR _a$[ebp]
mov DWORD PTR _b$[ebp], eax

; 8 : printf("%d, %d, %d, %d\n", a, *b, &a, b);

mov esi, esp
mov eax, DWORD PTR _b$[ebp]
push eax
lea ecx, DWORD PTR _a$[ebp]
push ecx
mov edx, DWORD PTR _b$[ebp]
mov eax, DWORD PTR [edx]
push eax
push 2
push OFFSET ??_C@_0BA@IJNICBJ@?$CFd?0?5?$CFd?0?5?$CFd?0?5?$CFd?6?$AA@
call DWORD PTR __imp__printf
add esp, 20 ; 00000014H
cmp esi, esp
call __RTC_CheckEsp

; 9 : int * c=const_cast<int *>(b);

mov eax, DWORD PTR _b$[ebp]
mov DWORD PTR _c$[ebp], eax

; 10 : printf("%d, %d\n", *c, c);

mov esi, esp
mov eax, DWORD PTR _c$[ebp]
push eax
mov ecx, DWORD PTR _c$[ebp]
mov edx, DWORD PTR [ecx]
push edx
push OFFSET ??_C@_07MHMABKGB@?$CFd?0?5?$CFd?6?$AA@
call DWORD PTR __imp__printf
add esp, 12 ; 0000000cH
cmp esi, esp
call __RTC_CheckEsp

; 11 : *c=4;

mov eax, DWORD PTR _c$[ebp]
mov DWORD PTR [eax], 4

; 12 : printf("%d, %d, %d, %d, %d, %d\n", a, &a, *b, b, *c, c);

mov esi, esp
mov eax, DWORD PTR _c$[ebp]
push eax
mov ecx, DWORD PTR _c$[ebp]
mov edx, DWORD PTR [ecx]
push edx
mov eax, DWORD PTR _b$[ebp]
push eax
mov ecx, DWORD PTR _b$[ebp]
mov edx, DWORD PTR [ecx]
push edx
lea eax, DWORD PTR _a$[ebp]
push eax
push 2
push OFFSET ??_C@_0BI@HAFKFEEE@?$CFd?0?5?$CFd?0?5?$CFd?0?5?$CFd?0?5?$CFd?0?5?$CFd?6?$AA@
call DWORD PTR __imp__printf
add esp, 28 ; 0000001cH
cmp esi, esp
call __RTC_CheckEsp

; 13 : const int e=a;

mov DWORD PTR _e$[ebp], 2

; 14 : printf("%d, %d, %d, %d\n", e, &e, &a, *(&a));

mov esi, esp
push 2
lea eax, DWORD PTR _a$[ebp]
push eax
lea ecx, DWORD PTR _e$[ebp]
push ecx
push 2
push OFFSET ??_C@_0BA@IJNICBJ@?$CFd?0?5?$CFd?0?5?$CFd?0?5?$CFd?6?$AA@
call DWORD PTR __imp__printf
add esp, 20 ; 00000014H
cmp esi, esp
call __RTC_CheckEsp

; 15 : int d=(int)&a;

lea eax, DWORD PTR _a$[ebp]
mov DWORD PTR _d$[ebp], eax

; 16 : printf("%d, %d, %d, %d, %d\n", a, &a, d, &d, *(int *)d);

mov esi, esp
mov eax, DWORD PTR _d$[ebp]
mov ecx, DWORD PTR [eax]
push ecx
lea edx, DWORD PTR _d$[ebp]
push edx
mov eax, DWORD PTR _d$[ebp]
push eax
lea ecx, DWORD PTR _a$[ebp]
push ecx
push 2
push OFFSET ??_C@_0BE@DHHNLGML@?$CFd?0?5?$CFd?0?5?$CFd?0?5?$CFd?0?5?$CFd?6?$AA@
call DWORD PTR __imp__printf
add esp, 24 ; 00000018H
cmp esi, esp
call __RTC_CheckEsp

; 17 : const int * f=&a;

lea eax, DWORD PTR _a$[ebp]
mov DWORD PTR _f$[ebp], eax

; 18 : printf("%d, %d\n", *f, f);

mov esi, esp
mov eax, DWORD PTR _f$[ebp]
push eax
mov ecx, DWORD PTR _f$[ebp]
mov edx, DWORD PTR [ecx]
push edx
push OFFSET ??_C@_07MHMABKGB@?$CFd?0?5?$CFd?6?$AA@
call DWORD PTR __imp__printf
add esp, 12 ; 0000000cH
cmp esi, esp
call __RTC_CheckEsp

; 19 : }

 

  看完了没...看完了估计你也懂了...汇编后...所有a的地方...统统都已经变成了 2 ...!!! 原来编译器是这么汇编的...

 

  恩……总结一下...1 尽信书不如无书 2 实践是检验真理的唯一标准 3 没有调查就没有发言权 4 不要凭主观臆断 不要想当然 5...

  完...

抱歉!评论已关闭.