1. 程式人生 > 實用技巧 >[C/C++知識點] volatile的含義及作用

[C/C++知識點] volatile的含義及作用

一、引言
由於記憶體訪問速度遠不及CPU處理速度,為提高機器整體效能,有兩種做法:
1、硬體上 引入硬體快取記憶體Cache,加速對記憶體的訪問。另外在現代CPU中指令的執行並不一定嚴格按照順序執行,沒有相關性的指令可以亂序執行,以充分利用CPU的指令流水線,提高執行速度。
2、軟體上
一種是在編寫程式碼時由程式設計師優化。另一種是由編譯器進行優化。
編譯器常用的優化方法有:將記憶體變數快取到暫存器。
由於訪問暫存器要比訪問記憶體單元快的多,編譯器在存取變數時,為提高存取速度,編譯器優化有時會先把變數讀取到一個暫存器中;以後再取變數值時就直接從暫存器中取值。但在很多情況下會讀取到髒資料,嚴重影響程式的執行效果。

二、volatile詳解
volatile關鍵字平常很少用到,我也是在用gdb定位一個問題的時候,嘗試修改某個變數的值,發現修改不了,想到將變數用volatile修飾之後便可以了。
volatile意思是“易變的,不確定的”。之所以“易變”是因為外在因素引起的,如多執行緒,中斷等。
volatile提醒編譯器它後面所修飾的變數隨時可能改變,因此編譯後的程式每次需要儲存或讀取這個變數的時候,告訴編譯器對該變數不做優化,都會直接從變數記憶體地址中讀取資料,從而可以提供對特殊地址的穩定訪問。如果沒有volatile關鍵字,則編譯器可能優化讀取和儲存,可能暫時使用暫存器中的值,如果這個變數由別的程式更新了的話,將出現不一致的現象。簡言之即volatile影響編譯器編譯結果,用volatile宣告的變量表示該變數隨時可能發生變化,與該變數有關的運算不要進行編譯優化,以免出錯。

三、舉例
先看以下兩段程式碼
1、不使用volatile修飾

#include "stdio.h"
 
int main()
{
    const int num = 10;
    int *p = (int *)#  // 思考:此處如果不加(int *)會怎樣。即int *p = #
       *p = 20;
    printf("num = %d\n", num);
    
    return 0;
}

這段程式,嘗試修改一個const修飾的變數,執行之後結果為10。(可能結果,也可能是20即修改成功,取決於編譯器是否進行了優化)

造成這種現象的原因是,在編譯期間,編譯器可能對程式碼進行優化。當編譯器看到此處的num被const修飾,考慮到num是不期望被修改的,所以優化的時候把n的值存放到暫存器中,以提高訪問的效率。只要後面使用num的地方都直接到暫存器中取,即使num在記憶體中的值發生變化,暫存器也不受影響,所以輸出的num的值為10。

2、使用volatile修飾

#include "stdio.h"
 
int main()
{
    volatile const int num = 10;
    
    int *p = (int *)#   
    *p = 20;
    printf("num = %d\n", num);
    
    return 0;
} 

執行結果20。
添加了volatile之後,num變成了20。volatile告知編譯器在進行編譯時不優化,在執行的時候不快取,每次都需要從記憶體中讀出。
volatile多用於多執行緒或多CPU程式設計。

四、注意
1、一個變數既可以是const也可以是volatile。
2、一個指標也可以是volatile。
3、頻繁地使用volatile很可能會增加程式碼尺寸和降低效能。