1. 程式人生 > >編譯器優化程式碼都幹了些什麼不為人知的事情?

編譯器優化程式碼都幹了些什麼不為人知的事情?

點選上方“程式人生”,選擇“置頂公眾號”

第一時間關注程式猿(媛)身邊的故事

首先介紹兩個優化概念

常量傳播

將編譯期間可計算出結果的變數轉換成常量,減少了變數的使用。

[cpp] view plain copy print?
int main()  
{  
    int nVar = 1;  
    printf("nVar = %d \n", nVar);  
}

變數 nVal 是一個在編譯期間可以計算出結果的變數,藉助常量傳播程式碼等價於:

[cpp] view plain copy print?
int main()  
{  
    printf("nVar = %d \n", 1);  
}

常量摺疊

當計算公式中出現多個變數進行計算的情況時,且編譯器可以在編譯期間計算出結果時,用結果代替所有的常量計算。

[cpp] view plain copy print?
int main()  
{      
    int nVar = 1 + 6 - 2 + 1 * 2;  
    printf("nVar = %d \n", nVar);  
}

"1 + 6 - 2 + 1 * 2"的值可以再編譯過程中計算出來,所以編譯器會將計算的結果代替原表示式

[cpp] view plain copy print?
int main()  
{  
    int nVar = 7;  
    printf("nVar = %d \n"
, nVar);  
}

此時變數 nVar 是一個在編譯期間可計算出結果的變數,在藉助「常量傳播」等價於:

[cpp] view plain copy print?
int main()  
{  
    printf("nVar = %d \n", 7);  
}

編譯器在 release 模式,會嘗試使用常量替換掉變數,如果在程式的執行過程中,宣告的變數沒有沒修改過,而且上下文中不存在對該變數的取地址和節間訪問操作,那麼這個變數就會被替換為常量。使用常量的好處是可以生成立即定址的目的碼,減少記憶體的訪問次數,提高效率。

下面我們把變數的初始值修改為一個在編譯期間無法確定的值,命令列引數的個數 argc,編譯器無法在編譯過程中得知結果,所以變數也就不會被常量替換掉。

argc 的含義是 argument count:它是一個 int 行變數,表示傳遞給 main 函式的引數數量;

argv 的含義是 argument value(值):它是一個指向字串的指標陣列,每個指標元素指向各個具體的引數;

[cpp] view plain copy print?
#include <stdio.h>  
 
int main(int argc, char* argv[])  
{  
               int nVarOne = argc ;  
               int nVarTwo = argc ;  
 
              nVarOne = nVarOne + 1;  
              nVarOne = 1 + 2;  
              nVarOne = nVarOne + nVarTwo;  
              printf( "nVarOne = %d \n" ,nVarOne);  
               return 0;  
}

優化後:

[cpp] view plain copy print?
#include <stdio.h>  
 
int main(int argc, char* argv[])  
{  
//             int nVarOne = argc; 被常量代替  
//             int nVarTwo = argc; 後面沒有對nVarTwo修改 等價於引用argc nVarTwo被刪掉(複寫傳播)  
//  
//             nVarOne = nVarOne + 1; 可計算 被刪除  
//             nVarOne = 1 + 2;   常量摺疊 等價於nVarOne = 3;  
//             nVarOne = nVarOne + nVarTwo; 常量傳播 複寫傳播等價於 nVarOne = 3 + argc;  
 
//             printf("nVarOne = %d \n",nVarOne);  
//  在輸出之前沒有對nVarOne進行操作輸出等價於  
              printf( "nVarOne = %d \n" ,3 + argc );  
               return 0;  
}

點選圖片get往期內容

640?wx_fmt=jpeg

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=gif