gcc編譯器優化給我們帶來的麻煩???


gcc編譯器優化給我們帶來的麻煩???

今天看到一個很有趣的程序,如下:

?
1
2
3
4
5
6
7
8
9
int  main()
{
     const  int  a = 1;
     int  *b = ( int *)&a;
     *b = 21;
 
     printf ( "%d, %d" , a, *b);
     return  0;
}

當我第一眼看到這個程序的時候,我想當然的認為輸出結果是21, 21,但是我錯了

一時很難理解,於是我又輸出了它們的地址:

?
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不同之處在於:

1,指令格式為:指令名稱 元操作數 目的操作數

2,寄存器前加%

3,操作數前加$

4,0x4(%esp)為內存尋址,實際表示的是esp寄存器中的內容 + 4(如果不是很明白,望自行查找資料,本人知識有限)

我們首先看標號為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賦值時編譯器用的是數值,並沒有引用地址。

所以,個人猜測,編譯器在這方面有一個優化功能:如果一個變量在定義時賦值常量,那么在引用它的時候,編譯器會直接用該常量數值代替地址的引用來節省時間,但是也給我們帶來了以外的麻煩。

這些都是個人的觀點,希望各位指教!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM