標籤:

C++中改變了const變數的值,但輸出卻沒有改變,而內存中數據的確變了,這是怎麼回事?

純粹是剛剛跟別人討論的時候瞎寫出來的一段代碼

代碼如圖:

監視窗口 顯示 n 已經被改變:

然而輸出結果:

非常神奇的是,p 與 n 是相等的,但 *p 跟 n 卻不是相等的。

然後我看了下彙編:

就是說,所有出現 n 及優化成 n 的地方(比如 *n),都被直接用 13 代替了。

對此我是理解的,因為一個常量是「絕對不可能」被改變的,雖然我的確這麼做了。

其實我的疑問在寫這個問題的時候就已經自己解決了,但寫了這麼多,還是得隨便找點東西問下:

既然存儲在內存中的常量並不會被使用到,那為什麼還要存儲一份在裡面呢?

我剛剛試了一下,即使是不使用 n 這些語句的情況下,還是會在內存中存儲一份這樣的數據。但實際上這個東西是不會被用到的。在這種情況下,這是完全沒有意義的吧,那為什麼不這樣優化?


改const變數的值,屬於結果未定義。所以出什麼亂子都不奇怪。

另一方面,你的編譯器在遇到*(int*)int(n)的時候,因為看到前面n已經聲明為const,就直接把這行變成13了。這是優化器做的。和你改不改值沒關係。存一份是為了你可以n。

總之,還是強調一遍,結果未定義。


理解這個的重點有2個:

1,任何一個變數都是有地址的,只有常量會在編譯預處理中處理成符號,但const類型不是常量,是一個只讀的變數,因此他是有地址的;

2,正確理解編譯行為和運行行為,簡單的說就是編譯器優化;

好了,來回到上面你的代碼:

1,8行,const int n = 13, 值為13

2,10-12,獲取到該變數的指針p,並且把裡面儲存的值改為10

3,13行,m = n,因為n是一個const 變數,編譯器優化掉了(這時還僅僅只是編譯行為,還沒來到運行階段呢,所以不要去想到這個地址裡面的值已經變成了10),相當於直接寫成m = 13

其他就沒什麼好說的了,只重點說說第18行,在現在流行的編譯器中,如果要說行為未定,也就只有這一行了,*n,可以做成編譯行為,也可搞成運行行為;


const實際上用來代替define,define太靈活,容易出錯,沒有類型。

對於const有沒有存儲空間,要分開來看。

如果是臨時變數,局部變數,沒有指針引用,優化之後就沒有,沒有優化還在。

對於全局變數,優化之後還有。

你這個代碼如果改成全部變數,你修改值之後,當前文件代碼使用還是原值,其他代碼使用,就是新值。


const int n = 13;

編譯器在編譯過程中將n保存在符號表中,並沒有為n開闢地址空間.輸出n的時候僅僅是用13替換掉,類似於#define的constant folding.


效率,複製一份放通用寄存器里找起來快。 不想有備份產生可以加voliate試試。

voliate const int n =13;

可能x86中並不是放在通用寄存器,或許是cache中,學藝不精,不過效率提高應該是實在的。


推薦閱讀:

如何才能自學編程並學好編程?
系統調用真正的效率瓶頸在哪裡?
C語言中,scanf("%d", &a),在設計這個語法結構時為什麼要有地址符&,沒有行不行?
有沒有求多邊形的狹窄部分的演算法?
寫不出數據結構的人是不是不適合編程?

TAG:編程 | C |