程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> gcc編譯器優化給我們帶來的麻煩???

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

編輯:關於C語言

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

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賦值時編譯器用的是數值,並沒有引用地址。

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

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved