何謂常量摺疊?
常量摺疊就是將常量表達式計算求值,並用求得的值來替換表達式,放入常量表。可以算作一種編譯優化。(預編譯階段)
接下來我們通過一段代碼來分析一下了解一下常量摺疊及其特性:
int main()
{
const int a = 10;
int b = 2*a;
int c = b;
int *p = (int*)&a;
*p = 100;
cout << a << endl;//輸出10
cout<< *p<<endl;//輸出100
return 0;
}
1 編譯器會爲該常量在棧上分配一塊空間。
const int a = 10;
0099446E mov dword ptr [a],0Ah
a是一個常量,按理說常量是存儲在代碼段的,可通過反彙編可以清楚地看到編譯器確實爲a在棧上分配了一塊空間。
在這一點上const常量和宏是有區別的,宏在預編譯階段就完成了替換,編譯器並不會爲宏分配空間。
2 代碼中遇上a的地方,直接替換爲a的值
下面我們來比較一下常量摺疊和正常變量的賦值
int b = 2*a;//常量摺疊賦值
00994475 mov dword ptr [b],14h//真正的實現形式是int b=2*10
int c = b;//正常變量賦值
0099447C mov eax,dword ptr [b]//藉助寄存器eax把b的值傳遞給c
0099447F mov dword ptr [c],eax
3
大家是否對上面代碼中最後的輸出結果有疑惑?
指針p指向a在棧上的空間,而且明明通過*p=100對該空間上的內容作出了改變,爲什麼輸出的a依舊是10呢?
話不多說,我們來看反彙編:
int *p = (int*)&a;
00994482 lea eax,[a] //通過寄存器eax把a的地址給指針p
00994485 mov dword ptr [p],eax
*p = 100;
00994488 mov eax,dword ptr [p]
0099448B mov dword ptr [eax],64h//修改p指向的空間的內容
cout << a << endl;
00994491 mov esi,esp
00994493 push 99149Ch
00994498 mov edi,esp
0099449A push 0Ah//出現a的地方直接用10代替
0099449C mov ecx,dword ptr ds:[9A00ECh]
009944A2 call dword ptr ds:[9A0094h]
009944A8 cmp edi,esp
009944AA call __RTC_CheckEsp (0991325h)
009944AF mov ecx,eax
009944B1 call dword ptr ds:[9A00F4h]
009944B7 cmp esi,esp
009944B9 call __RTC_CheckEsp (0991325h)
從上面的彙編代碼中可以看到,a所在地址上的內容確實已經被p所修改,a的值已被改變,但是在輸出a的時候,編譯器輸出的並不是該空間上的內容,而是直接用10替換了。