我想任何對 C++ 有基本認識的人都會同意 const 比 #define 出來的常數還好--有明確的 type、scope,這些已經不必多說。

不過好像有不少人認為兩者生成的機器碼仍有所差異,const 似乎有比較多的 overhead。他們的想法是這樣的:

1) 用 #define 定義出來的常數經 preprocessor 取代後,數值會直接成為機器指令的 immediate value

2) 用 const 定義出來的常數是一個可定址的資料,執行時會在 scope 對應的的記憶體,例如stack,上面配置一小塊空間,然後將值存放在上面。

順著這個邏輯推下去會產生一個迷思:const 和 #define 有可能在低階有不同的表現,像是執行速度和 binary size 等等。舉例來說,immediate value 直接屬於機器指令的一部分,執行時隨指令載入;然而 const data 在執行時還得讀取另一個記憶體位址。

真的如此嗎?不正確。

關於 1) 基本上沒甚麼問題,但 2) 則是和現實大不相同。幾乎像樣一點的編譯器都可以自動 evaluate 常算式,然後在生成機器語言的時候變成 immediate value。事實上,不論用 const 或 #define,大多數的編譯器都產生相同品質的機器碼。

那個理論上要額外建立的 const 常數既然派不上用場,所以編譯完就會徹底消失,根本就不會消耗執行時間和空間。唯一的例外是有人刻意凸顯 const 常數「可定址」這個特性,那麼編譯器才會不得不配置所需空間,但即便如此,其它不依賴此位址的程式碼還是會拿到 immediate value。

現代編譯器演算常算式的能力非常強,像下面這段程式碼就算完全不用const:

double pi = 3.14159;
int x = 10, y;

y = x * x * pi;
printf("%d\n", y);

你以為執行時會將 x 提升成 double、做浮點運算、再將結果轉 int、存回 y、最後才印出來嗎?

不。只要有開O2,最後只會直接編譯成 printf("%d\n", 314) 對應的目的碼,計算過程完全在編譯期就搞定了。編譯器甚至不會替 x、y、pi 這些變數生成任何目的碼,除非程式碼在其他地方試圖更改變數內容或取址。

這裡要說的結論是:const其實不會造成任何overhead,至少和 #define 相比是如此。const也不會帶來額外的效能改進,即使不加 const 編譯器也會努力找出可以在編譯期處理的常算式。

const所提供的只是更合理的語法限制而已,這也就夠了。

novus 發表在 痞客邦 PIXNET 留言(0) 人氣()