編譯器優化程式碼都幹了些什麼不為人知的事情?
阿新 • • 發佈:2019-02-19
點選上方“程式人生”,選擇“置頂公眾號”
第一時間關注程式猿(媛)身邊的故事
首先介紹兩個優化概念
常量傳播
將編譯期間可計算出結果的變數轉換成常量,減少了變數的使用。
[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往期內容