|
#include <iostream> using namespace std; int main(int argc, char *argv[]){ const int a = 10; int *p = (int *) &a;//讓p指向與a相同的內(nèi)存空間 cout << *p << " " << a << endl; cout << p << " " << &p << endl; *p = 20;// 照里說a的值也應該改變,實際卻沒有,這就是常量折疊. cout << *p << " " << a << endl; cout << p << " " << &p << endl; // 這個"常量折疊"就是在編譯器進行語法分析的時候,將常量表達式計算求值, // 并用求得的值來替換表達式,放入常量表??梢运阕饕环N編譯優(yōu)化。 // 我只是改了這個地址內(nèi)容,但是a還是, // 因為編譯器在優(yōu)化的過程中,會把碰見的const全部以內(nèi)容替換掉 // (跟宏似的: #define PI 3.1415,用到PI時就用.1415代替), // 這個出現(xiàn)在預編譯階段;但是在運行階段,它的內(nèi)存里存的東西確實改變了!(下面演示) return 0;} 輸出結(jié)果: 10 10 0xbfda9ccc 0xbfda9cc8 20 10 0xbfda9ccc 0xbfda9cc8 為了驗證在運行階段,a所在地址的內(nèi)容確實被*p = 20改變了,我們單步調(diào)試如下: Reading symbols from /home/beijibing/zixue/unp2/svshm/test...done. (gdb) b 9 Breakpoint 1 at 0x80487e7: file test.c, line 9. (gdb) run Starting program: /home/beijibing/zixue/unp2/svshm/test 10 10 0xbffff39c 0xbffff398 // 前兩個cout輸出后,我們知道了存a和p的堆棧地址。 Breakpoint 1, main (argc=1, argv=0xbffff454) at test.c:9 9 *p = 20; //在這里設(shè)了斷點,先暫停查看現(xiàn)在堆棧內(nèi)容 (gdb) x/2x 0xbffff398 //從低地址查看2個字的內(nèi)容 0xbffff398: 0xbffff39c 0x0000000a //可以看出0xbffff398中存放的是a的地址0xbffff39c,而0xbffff39c中存放的是0xa(10進制為10) (gdb) n 11 cout << *p << " " << a << endl; (gdb) x/2x 0xbffff398 0xbffff398: 0xbffff39c 0x00000014 //單步執(zhí)行后在查看,發(fā)現(xiàn)0xbffff39c中的值被改為0x14(20),正如上面所述 (gdb) n 20 10 12 cout << p << " " << &p << endl; (gdb) n 0xbffff39c 0xbffff398 19 return 0; (gdb)
總結(jié):編譯器會為常量分配了地址,但是在使用常量的時候,常量會被一立即數(shù)替換(保護常量,防止被破壞性修改) 在C++中對于基本類型的常量,編繹器并不為其分配存儲空間,編譯器會把它放到符號表,當取符號常量的地址等操作時,將強迫編譯器為這些常量分配存儲空間,編譯器會重新在內(nèi)存中創(chuàng)建一個它的拷貝,通過地址訪問到的就是這個拷貝而非原始的符號常量。 和C語言中const常量對比: #include <stdio.h> int main() { const int a = 10; int *p = (int *) &a; printf("%d, %d\n",*p,a) ; printf("%x, %x\n",p,&p) ;
*p = 20; // a = 30; //常量是不能修改的,error: assignment of read-only variable 'a’ printf("%d, %d\n",*p,a) ; printf("%x, %x\n",p,&p) ; return 0; } 編譯運行結(jié)果: 10, 10 bfea80fc, bfea80f8 20, 20 bfea80fc, bfea80f8 可以查看二進制文件,發(fā)現(xiàn)a并沒有在鏈接的時候占用.rodata空間。 注意:可以看出a被修改了,a是在棧上分配的常量,a本身不能修改,但是可以用指針p指向a,然后修改p指向的內(nèi)容,這樣就可以修改常量a的內(nèi)容了。
|
|
|