3

Possible Duplicate:
Modifying a const through a non-const pointer

lets' see the code below first.very short code:

int main()
{
    const int n=9;
    int *p=(int*)&n;
    *p=5;
    cout<<*p<<endl; //result is 5
    cout<<n<<endl;  // 9
    int a=n+1;
    cout<<a<<endl;  // 10
}

To my surprise,the compiler doesn't complain at all.And the result is as what i showed as comment.
But,if that makes sense more or less.What's more astonishing is that, when you debug it, you can see that the value of n has actually changed to 5!
But then ,when you use "n",it seemed that the "n" is still treated as the original value 9!
So i guess the compiler has stored the original value of "n" in somewhere else, right? Then where is the original value of "n",which is 9, stored now?
Thank you for all your help!

Community
  • 1
  • 1
duleshi
  • 1,966
  • 2
  • 21
  • 32
  • 2
    You broke the rules. There are no guarantees at all on what the compiler gives you in return. – Ben Voigt Jul 25 '12 at 01:54
  • yes.i know.Actually we should never use it like that. But it's interesting,right? I'm just curious about the hidden behavior. And i think it can do good to improving. :) – duleshi Jul 25 '12 at 02:17

1 Answers1

3

This probably due to optimizations. Since you declare const int n=9, you're basically making a promise that you won't modify n. So the compiler is free to optimize cout << n << endl; to a simple cout << 9 << endl;. I don't think the old value is stored anywhere else.

Nevertheless, this is undefined behavior.

I can confirm that the cause of this behavior is optimization, even on a debug build:

    cout<<n<<endl;  
01151426  mov         esi,esp  
01151428  mov         eax,dword ptr [__imp_std::endl (11582B4h)]  
0115142D  push        eax  
0115142E  mov         edi,esp  

//HERE:
//
01151430  push        9  
//
//

01151432  mov         ecx,dword ptr [__imp_std::cout (11582B0h)]  
01151438  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (11582ACh)]  
0115143E  cmp         edi,esp  
01151440  call        @ILT+325(__RTC_CheckEsp) (115114Ah)  
01151445  mov         ecx,eax  
01151447  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (11582A8h)]  
0115144D  cmp         esi,esp  
0115144F  call        @ILT+325(__RTC_CheckEsp) (115114Ah)  

n doesn't even come into discussion.

If n wasn't const, the optimization would be illegal:

00D51426  mov         esi,esp  
00D51428  mov         eax,dword ptr [__imp_std::endl (0D582B4h)]  
00D5142D  push        eax  
00D5142E  mov         edi,esp  

//HERE
//
00D51430  mov         ecx,dword ptr [n]  
00D51433  push        ecx  
//
//

00D51434  mov         ecx,dword ptr [__imp_std::cout (0D582B0h)]  
00D5143A  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0D582ACh)]  
00D51440  cmp         edi,esp  
00D51442  call        @ILT+325(__RTC_CheckEsp) (0D5114Ah)  
00D51447  mov         ecx,eax  
00D51449  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0D582A8h)]  
00D5144F  cmp         esi,esp  
00D51451  call        @ILT+325(__RTC_CheckEsp) (0D5114Ah)  

Here, the value of n is pushed on the argument stack because it's not const.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625