2012-01-14 47 views
6

我正在讀一本書如果編譯器知道每一個使用const的,其中提到這存儲分配爲const變量

,它不需要分配 空間來容納它。例如:

  1. const int c1=1;
  2. const int c3=my_f(3);
  3. extern const int c4;

由於C3和C4值不被稱爲編譯時間,存儲 必須分配C3和C4。

我不明白這一點。我的疑惑是:

這是什麼意思?難道它仍然不需要將所有內容都存儲在內存中嗎? 對於c1,我們是否有任何存儲分配?

請清除我的疑惑。

謝謝。

+1

'c2'發生了什麼事? – 2012-01-14 16:16:48

回答

4

c1與其他兩個常量的不同之處在於它使用文字值進行初始化。這讓編譯器把該值到處常數時,像這樣:

int x = z + c1; 

可以通過

int x = z + 1; 

更換這意味着,編譯器並不需要分配空間和存儲1在裏面。

c3c4是不同的:一個是使用函數計算的,另一個是從不同的編譯單元提供的。這意味着編譯器不能再像c1那樣執行替換:編譯器不知道c3c4的值。因此,編譯器以相同的方式,如同c4被存儲在存儲器中的某些地方的變量產生用於

int x = z + c4; 

代碼。由於在這種情況下,c4是一個外部常量,鏈接器將解析其位置,並填寫編譯器丟失的信息(即地址c4),以使程序完成並準備運行。

+0

感謝您的回答,但那是否意味着每當一個變量被定義爲一個const並且用一個文字初始化時,它就像一個宏,並且在程序中的任何地方使用編譯器justs將該變量替換爲值? – 2012-01-14 15:52:40

+1

@Leoheart編譯器被允許*做替換,大多數編譯器都這麼做。但據我所知,編譯器不必「內聯」已聲明的常量:標準允許它們以任何方式執行。此外,您可以使用已聲明常量的地址,在這種情況下,編譯器將它放在內存中,除了在使用它的地方內聯它。 – dasblinkenlight 2012-01-14 16:00:53

+0

明白了。謝謝。 – 2012-01-14 16:12:51

1

作爲一個整型常量表達式,編譯器完全有權使用常量摺疊將其從程序中刪除。如果你把它的地址,這是不正確的。另外,如果可能的話,現代優化編譯器可以使用LTO,內聯和常量摺疊來對c3和c4執行相同的操作。

如果您不接受變量的地址,那麼編譯器沒有義務分配它,只要它能夠在as-if規則下生成具有相同結果的代碼。

編輯:常量摺疊是編譯器在編譯時而不是運行時評估表達式的地方。例如,您可以合法地執行int x[3 + 4];,其中3 + 4在編譯時進行評估。一些例子,特別是那些涉及ICE的例子,是標準規定的,但如果可能的話,實施可以執行更多。 LTO是鏈接時間優化,當編譯器鏈接在一起時,編譯器執行跨轉換單元的優化。

這意味着,編譯器可以內聯體的my_f,然後(取決於身體)恆定折出來,使c3常量表達式,然後恆定倍它變成無論它的使用,並且不分配它。對於c4,LTO可能會產生值c4作爲常量表達式,在這種情況下,它可以不斷摺疊並刪除。

在C++ 11中有constexpr函數,允許在這個區域做更多的事情。

+0

我很抱歉,我無法理解您的答案。什麼是不斷摺疊和LTO? – 2012-01-14 15:49:44

+0

明白了。謝謝。 – 2012-01-14 15:54:54

+0

最後一個問題:這是否意味着每當一個變量被定義爲一個const並且用一個文字進行初始化時,它就像一個宏,並且在程序中的任何地方使用編譯器justs將該變量替換爲值? – 2012-01-14 15:57:03

2

Const有2種用法 - 替換宏(常量表達式)和不可變數據。

本聲明:

const int c1=1; 

主要是這種類型安全的版本:

#define c1 1 

,使得該代碼:

int foo = c1; 

可以簡單地被編譯爲:

int foo = 1; 

哪個更有效。

在另一方面,這樣的:

const int c3=my_f(3); 

被用作一個不變的C3。它可能存在於內存中,但不能修改它。它本質上是一個更安全的版本int c3=my_f(3);

爲了說明這一點:

int a1[c1]; 
int a2[c3]; 

a1爲有效的,因爲編譯器可以推斷a1至是常量表達式。 a2不是,因爲c3是const的,它在編譯時可能不知道。

C++ 11添加了與const類似的constexpr關鍵字,雖然比const更嚴格。只有c1c2可能是constexprc3也可以,但它也需要my_f也是。