【软件开发底层知识修炼】二十八 C/C++中volatile的作用
- 上一篇文章學習了C/C++中的指針與數組的區別,點擊鏈接進行查看:【軟件開發底層知識修煉】二十七 C/C++中的指針與數組是不同的
- 本篇文章將學習volatile關鍵字在C/C++中的作用
文章目錄
- 1 實例代碼分析
- 2 問題分析
- 3 解決方案
- 4 拓展: const和volatile
- 4 總結
1 實例代碼分析
在講解volatile關鍵字的作用之前,我們先來看一個代碼的例子,代碼如下:
- main.c
- device.c
上面的代碼,是非常容易懂的,這里就不再多說。我們直接編譯運行看看:
- gcc -pthread main.c device.c -o test.out
- ./test.out
運行結果如下:
這個結果對于我們來說其實挺容易懂的。就是main中的while循環先每隔一秒打印執行一次,然后5秒后th_fn函數開始執行,th_fn函數將g_ready變量變為1,然后打印一個語句。最后回到main中的while循環,由于while中上次最后一秒現在才執行完,打印一句,然后由于此時g_ready為1,所以退出循環,然后打印循環外的一個語句,然后結束程序的運行。這種結果,其實是比較容易理解的。也是比較普遍的結果。
但是如果我們再編譯上述代碼的時候,加上了-O3選項,該選項是優化選項,且級別比較高。編譯運行結果如下:
- gcc -O3 -pthread main.c device.c -o test.out
- ./test.out
運行結果如下動態圖:
由以上結果我們可以看到,程序陷入了死循環,g_ready沒有被改變一直都是0,所以main中的while循環一直在執行。對于這個結果,可能并不是所有人都知道為什么。下面,我們就要來講解為什么會產生上面的運行結果。
2 問題分析
-O3選項是讓編譯器對代碼進行優化。
- 編譯優化時,編譯器根據當前文件進行優化。
- 為了效率上的提高,優化時編譯器將變量值從內存中讀取進入寄存器
- 每次要訪問變量時直接從寄存器讀取。畢竟寄存器的存取比內存的存取快很多。
那么,我們明白了優化對變量的影響。對于上述的代碼,如果在編譯時加了-O3選項。編譯優化時,編譯器會將變量g_ready的值放到寄存器中,以后每次使用該變量就從寄存器中取出g_ready的值使用即可。這樣雖然是速度快了,但是當在th_fn函數中改變了g_ready的值后,在內存中確實g_ready的值已經變為1了,但是在剛剛那個寄存器中,最開始將g_ready的值也就是0存進去的,一直都沒有改變過,但是呢,由于編譯器的優化,每次在使用g_ready的變量的時候,都是從寄存器中直接取出值來使用…
說到這里,應該都能夠明白了,此時從寄存器中取出的值就一直都是0.然后while一直循環。
3 解決方案
編譯的時候使用-O3選項是很常用的。那么如何才能既使用這個-O3選項,又使得上述程序按照我們的意愿來執行呢?volatile就此出場。
使用volatile關鍵字修飾可能被意外修改的變量(內存),從而禁止編譯器對該變量進行優化。
- volatile一般修飾的是一種易變的變量
- volatile可理解為一種編譯器警告指示字,它告訴編譯器必須每次都直接去內存中取變量值。
那么在上述的代碼中,我們將main.c中的extern const int g_ready; 改為:extern volatile const int g_ready; 再重新進行優化的編譯,然后運行,結果就是正確的運行。可以自己嘗試做實驗!
4 拓展: const和volatile
細心的朋友會發現,在main.c程序中,我們改完后,成這樣了:extern volatile const int g_ready; 又是const又是volatile的。我們上面說過,volatile修飾的是意變的變量,而const修飾的變量是不能被修改的,有的人叫它常量,不可變的。而實際上在編程語言中的解釋是這樣的:const修飾的變量在當前文件中不能夠出現在賦值符號的左邊。 所以我們可以看到,在main.c這個文件中g_ready這個變量,并沒有出現在賦值符號的左邊,所以是沒有問題。但是在device.c文件中g_ready是沒有被const修飾的,它就可以出現在賦值符號的左邊,可以被改變。這樣一來,在device.c中修改g_ready這個變量,在main.c中的g_ready也間接被改變了。所以,我覺得說const修飾的是常量這個說法不夠準確,說它是變量但是不能夠出現在賦值符號的左邊更加準確。
下面就總結一下const和volatile關鍵字:
- const表示修飾的變量在當前文件中不能出現在賦值符號的左邊,不能直接被改變,但是可以間接被改變
- volatile表示修飾的變量每次使用的時候直接從內存中讀取
- const和volatile同時修飾變量時互不影響。
4 總結
- 編譯優化時,編譯器僅根據當前文件進行優化
- 編譯器的優化策略可能造成一些意外
- volatile強制編譯器必須從內存中取變量值
- const和volatile同時修改變量時,互相不影響彼此的含義。
總結
以上是生活随笔為你收集整理的【软件开发底层知识修炼】二十八 C/C++中volatile的作用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 娃哈哈的新品,为什么打动不了年轻人?
- 下一篇: s3c2440移植MQTT