C 的常量摺疊(三)

2022-04-10 13:58:20 字數 1678 閱讀 3729

背景知識

符號表是一種用於語言翻譯器中的資料結構。在符號表中,程式源**中的每個識別符號都和它的宣告或使用資訊繫結在一起,比如其資料型別、作用域以及記憶體位址。

符號表在編譯程式工作的過程中不斷收集、記錄和使用源程式中一些語法符號的型別和特徵等相關資訊。這些資訊一般以**形式儲存於系統中。如常數表、變數名錶、陣列名表、過程名錶、標號表等等,統稱為符號表。對於符號表組織、構造和管理方法的好壞會直接影響編譯系統的執行效率。

還有乙個問題:前面說的似乎很讓人煩,既然宣告成了const,幹嘛還老修改啊?

根據c++標準,對於修改const變數,屬於:未定義行為(指行為不可**的計算機**),這樣一來此行為取決於各種編譯器的具體實現(即不同編譯器可能表現不同)。

看到了吧,c++標準是不提倡這麼玩的。

下面看一下前面說的那個對照程式:

int

main()

同時把i的宣告那條語句改成:

const

volatile

int i = 0; //

定義常量i

我們知道volatile是告訴編譯器在翻譯原始碼到組合語言(機器碼)的過程中,不要優化。把原始碼中對i的訪問,翻譯成每次都要去記憶體中抓取資料(這裡是在做編譯工作,只是把對應的原始碼翻譯成組合語言),而不是從符號表(常量表)中抓取資料。所以加上volatile關鍵字的i的訪問都是去記憶體中拿資料,不去常量表中。

現在還有個問題,如果我加上volatile關鍵字,那麼每次對i的訪問的語句都被翻譯成了」去看記憶體裡的資料「這種行為的組合語言,不會有常量替換的過程了,那麼下面的語句是不是合法了呢?

i = 10;
你修改了常量的值,怎麼可能合法呢?但是按照上面的說法對於const volatile int型別的i似乎又是合法的。問題出在了這裡:

編譯器的一部分工作流程是這樣的:語法檢測->預編譯(巨集替換,常量替換,*(&i)恆等於i等優化)->編譯。所以i = 10這句話在語法檢查這個階段,看到你對乙個const常量賦值,就已經報錯了,根本到不了編譯這個階段。

但是有的一些編譯器似乎無視這個volatile關鍵字,下面看一下測試的結果:

(1)看vc6.0的結果:

沒有volatile關鍵字的:

有volatile關鍵字的:

即在vc++6.0編譯環境下,在const變數定義時新增volatile修飾符,與不新增效果是一樣的。編譯器都採取了優化(甚至把編譯器優化選項關閉還是如此,無奈了)。

(2)vs2010和g++的測試結果是一樣的:

沒有volatile關鍵字:

有volatile關鍵字:

所以:不建議修改const變數的值,即使修改也要熟悉當前使用的編譯器對於該 未定義行為 是如何解釋的

C 常量摺疊

c 中const 常量用法 說明 c語言中const 常量可以很容易地被改變 include include void main c 編譯器進行語法分析的時候,將常量表示式計算求值,並用求得的值來替換表示式,放入常量表,是 因為編譯器在優化的過程中,會把碰見的const全部以內容替換掉 跟巨集替換類...

c 中的常量摺疊

先來看乙個例子 include int main 這就是編譯器的 常量摺疊 在作怪啦!常量摺疊 就是在編譯器進行語法分析的時候,將常量表示式計算求值,並用求得的值來替換表示式,放入常量表。可以算作一種編譯優化。編譯器在優化的過程中,會把碰見的const全部以內容替換掉 跟巨集替換似的 define ...

常量摺疊解析

include using namespace std intmain test的位址為 009afa44 test的值為 10 p的位址為 009afa44 p的值為 20 int main void const tt s cout s s.a tt result const cast s res...