今天看到一個頗有趣的程序,以下:優化
int main() { const int a = 1; int *b = (int*)&a; *b = 21; printf("%d, %d", a, *b); return 0; }
當我第一眼看到這個程序的時候,我想固然的認爲輸出結果是21, 21,可是我錯了blog
一時很難理解,因而我又輸出了它們的地址:內存
int main() { const int a = 1; int *b = (int*)&a; *b = 21; printf("%d, %d", a, *b); printf("\n%p, %p", &a, &*b); return 0; }
它們的地址是同樣的,看到這裏我更加的不解,因而我試着查看一下彙編代碼。編譯器
int main() { const int a = 1; int *b = (int*)&a; *b = 21; printf("%d", a); return 0; }
對應彙編代碼以下:編譯
這裏獲得的是at&t的彙編代碼,與intel不一樣之處在於:class
1,指令格式爲:指令名稱 元操做數 目的操做數變量
2,寄存器前加%引用
3,操做數前加$程序
4,0x4(%esp)爲內存尋址,實際表示的是esp寄存器中的內容 + 4(若是不是很明白,望自行查找資料,本人知識有限)im
咱們首先看標號爲1的行,對應c語句爲const int a =1,這是把1放進地址爲0x18(%esp)的地方,再來看標號2的地方,對應的printf語句,發現並無引用地址爲0x18(%esp)的地方的值,而是把1直接放到了0x4(%esp),而後輸出。
因此我的認爲,之因此會出現最開始的結果,是由於編譯器給咱們作了一些優化致使的。爲了證實個人觀點,我修改了程序:
int main() { int c = 1; const int a = c; int *b = (int*)&a; *b = 21; printf("%d, %d", a, *b); return 0; }
輸出結果爲:
對應的彙編代碼爲:
在標號1處,咱們能夠肯定a存放在0x14(%esp)的地方,在標號2處,對應的printf語句,此語句從右向左處理參數,2處理的是*b,3處理的是a,這時看到用的是地址,而不是直接用數值,同時看標號0處,咱們是將c賦值1,再給a賦值時編譯器用的是數值,並無引用地址。
因此,我的猜想,編譯器在這方面有一個優化功能:若是一個變量在定義時賦值常量,那麼在引用它的時候,編譯器會直接用該常量數值代替地址的引用來節省時間,可是也給咱們帶來了之外的麻煩。
這些都是我的的觀點,但願各位指教!!!