C/C++ volatile關鍵字
1. 為什麼用volatile?
C/C++ 中的 volatile 關鍵字和 const 對應,用來修飾變數,通常用於建立語言級別的 memory barrier。這是 BS 在 “The C++ Programming Language” 對 volatile 修飾詞的說明:
A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the language so that aggressive optimizations must be avoided.
volatile 關鍵字是一種型別修飾符,用它宣告的型別變量表示可以被某些編譯器未知的因素更改,比如:作業系統、硬體或者其它執行緒等。遇到這個關鍵字宣告的變數,編譯器對訪問該變數的程式碼就不再進行優化,從而可以提供對特殊地址的穩定訪問。宣告時語法:int volatile vInt; 當要求使用 volatile 宣告的變數的值的時候,系統總是重新從它所在的記憶體讀取資料,即使它前面的指令剛剛從該處讀取過資料。而且讀取的資料立刻被儲存。例如:
//... volatile int i = 10; int a = i; //... // 其他程式碼,並未明確告訴編譯器,對 i 進行過操作 int b = i;
volatile 指出 i 是隨時可能發生變化的,每次使用它的時候必須從 i 的地址中讀取,因而編譯器生成的彙編程式碼會重新從i的地址讀取資料放在 b 中。而優化做法是,由於編譯器發現兩次從 i讀資料的程式碼之間的程式碼沒有對 i 進行過操作,它會自動把上次讀的資料放在 b 中。而不是重新從 i 裡面讀。這樣以來,如果 i是一個暫存器變數或者表示一個埠資料就容易出錯,所以說 volatile 可以保證對特殊地址的穩定訪問。
下面編寫程式並通過插入彙編程式碼,測試有無volatile關鍵字,對程式最終程式碼的影響。
輸入下面的程式碼:
發現上面的程式在Debug,Release模式下的輸出都是:#include <stdio.h> void main() { int i = 10; int a = i; printf("i = %d\n", a); // 下面彙編語句的作用就是改變記憶體中 i 的值 // 但是又不讓編譯器知道 __asm { MOV DWORD PTR[EBP - 4], 20H } int b = i; printf("i = %d\n", b); }
這個程式在Debug,Release模式下的輸出一致,說明預設情況下VC++ 10.0在兩種模式下都做了程式碼優化,都造成了編譯無法識別變數的改變。
再輸入下面的程式碼:
#include <stdio.h>
void main()
{
volatile int i = 10;
int a = i;
printf("i = %d\n", a);
// 下面彙編語句的作用就是改變記憶體中 i 的值
// 但是又不讓編譯器知道
__asm
{
MOV DWORD PTR[EBP - 4], 20H
}
int b = i;
printf("i = %d\n", b);
}
發現上面的程式在Debug模式下的輸出也是:
但是在Release模式下的輸出是:
上面這個程式在不同模式下的輸出說明這個 volatile 關鍵字只在 Release 模式下才發揮了它的作用,在 Debug 模式下並沒有達到想要的結果。這也說明,在使用 volatile 修飾符修飾變數時,需要注意程式在 Debug 模式和 Release 模式下的不同行為。
其實不只是“內嵌彙編操縱棧”這種方式屬於編譯無法識別的變數改變,另外更多的可能是多執行緒併發訪問共享變數時,一個執行緒改變了變數的值,怎樣讓改變後的值對其它執行緒
visible。一般說來,volatile 用在如下的幾個地方:
1) 中斷服務程式中修改的供其它程式檢測的變數需要加 volatile;
2) 多工環境下各任務間共享的標誌應該加 volatile;
3) 儲存器對映的硬體暫存器通常也要加 volatile 說明,因為每次對它的讀寫都可能由不同意義。
自己的註解:自己在之前的 MCU 程式的編寫,以及在多執行緒程式的編寫中,從來沒有用到 volatile 修飾符修飾變數。比如在微控制器的 C51 程式設計中似乎身邊的人都沒有用過該修飾符,查閱《微控制器的 C 語言應用程式設計》一書也沒有講解關於 volatile 的內容,這不禁讓我懷疑是不是 Keil C51 編譯器對這一塊的預設支援,即 Keil C51 編譯器就不會有上面的優化過程,這一點,自己還需要進一步考證。
2.volatile 指標
和 const 修飾詞類似,const 有常量指標和指標常量的說法,volatile 也有相應的概念:
-
修飾由指標指向的物件、資料是 const 或 volatile 的:
const char* cpch;
volatile char* vpch;
注意:對於 VC,這個特性實現在 VC 8 之後才是安全的。
指標自身的值——一個代表地址的整數變數,是 const 或 volatile 的:
char* const pchc;
char* volatile pchv;
注意:
(1) 可以把一個非 volatile int 賦給 volatile int,但是不能把非 volatile 物件賦給一個 volatile 物件。
(2) 除了基本型別外,對使用者定義型別也可以用 volatile 型別進行修飾。
(3) C++ 中一個有 volatile 識別符號的類只能訪問它介面的子集,一個由類的實現者控制的子集。使用者只能用 const_cast 來獲得對型別介面的完全訪問。此外, volatile 向 const 一樣會從類傳遞到它的成員。
3. 多執行緒下的 volatile
有些變數是用 volatile 關鍵字宣告的。當兩個執行緒都要用到某一個變數且該變數的值會被改變時,應該用 volatile 宣告,該關鍵字的作用是防止優化編譯器把變數從記憶體裝入 CPU 暫存器中。如果變數被裝入暫存器,那麼兩個執行緒有可能一個使用記憶體中的變數,一個使用暫存器中的變數,這會造成程式的錯誤執行。volatile 的意思是讓編譯器每次操作該變數時一定要從記憶體中真正取出,而不是使用已經存在暫存器中的值,如下:
volatile BOOL bStop = FALSE;
(1) 在一個執行緒中:; while( !bStop ) { ... }
bStop = FALSE;
return;
(2) 在另外一個執行緒中,要終止上面的執行緒迴圈:bStop = TRUE;
while( bStop ); //等待上面的執行緒終止
如果 bStop 不使用 volatile 申明,那麼這個迴圈將是一個死迴圈,因為 bStop 已經讀取到了暫存器中,暫存器中 bStop 的值永遠不會變成 FALSE,加上 volatile,程式在執行時,每次均從記憶體中讀出 bStop 的值,就不會死迴圈了。
這個關鍵字是用來設定某個物件的儲存位置在記憶體中,而不是暫存器中。因為一般的物件編譯器可能會將其的拷貝放在暫存器中用以加快指令的執行速度,例如下段程式碼中:
...
int nMyCounter = 0;
for(; nMyCounter<100;nMyCounter++)
{
...
}
...
在此段程式碼中,nMyCounter 的拷貝可能存放到某個暫存器中(迴圈中,對 nMyCounter 的測試及操作總是對此暫存器中的值進行),但是另外又有段程式碼執行了這樣的操作:nMyCounter -= 1;這個操作中,對 nMyCounter 的改變是對記憶體中的 nMyCounter 進行操作,於是出現了這樣一個現象:nMyCounter 的改變不同步。
相關推薦
C語言學習及應用筆記之四:C語言volatile關鍵字及其使用
在C語言中,還有一個並不經常使用但卻非常有用的關鍵字volatile。那麼使用volatile關鍵字究竟能幹什麼呢?接下來我將就此問題進行討論。 一個使用volatile關鍵字定義變數,其實就是告訴編譯系統這變數可能會被意想不到地改變。那麼編譯時,編譯器就不會自作主張的去假設這個變數的值,而進行程式
C/C++中volatile關鍵字詳解
asm 運行 多線程並發 這樣的 修改 由於 設定 其他 硬件 1. 為什麽用volatile? C/C++ 中的 volatile 關鍵字和 const 對應,用來修飾變量,通常用於建立語言級別的 memory barrier。這是 BS 在 "The C++ P
c語言volatile關鍵字在微控制器中的作用
volatile 的意思是“易失的,易改變的”。這個限定詞的含義是向編譯器指明變數的內容可能會由於其他程式的修改而變化。通常在程式中申明瞭一個變數時,編譯器會盡量把它存放在通用暫存器中,例如ebx。當CPU把其值放到ebx中後就不會再關心對應記憶體中的值。若此時其他程式(例如
c#中volatile關鍵字的作用(zz)
恐怕比較一下volatile和synchronized的不同是最容易解釋清楚的。volatile是變 量修飾符,而synchronized則作用於一段程式碼或方法;看如下三句get程式碼: int i1; int geti1() {return
詳解C中volatile關鍵字
volatile提醒編譯器它後面所定義的變數隨時都有可能改變,因此編譯後的程式每次需要儲存或讀取這個變數的時候,都會直接從變數地址中讀取資料。如果沒有volatile關鍵字,則編譯器可能優化讀取和儲存,可能暫時使用暫存器中的值,如果這個變數由別的程式更新了的話,將出現不
C語言volatile關鍵字—最易變的關鍵字
volatile 是易變的、不穩定的意思。很多人根本就沒見過這個關鍵字,不知道它的存在。也有很多程式設計師知道它的存在,但從來沒用過它。我對它有種“楊家有女初長成,養在深閨人未識” 的感覺。volatile 關鍵字和const 一樣是一種型別修飾符,用它修飾的變量表示可以被
C#中的volatile關鍵字
ola 關鍵字 current ember oop doc test word sharp volatile 關鍵字指示一個字段可以由多個同時執行的線程修改。 聲明為 volatile 的字段不受編譯器優化(假定由單個線程訪問)的限制。 這樣可以確保該字段在任何時間呈現的都
C語言中volatile關鍵字的作用
本文為轉載總結文章:點選進入原地址 用volatile修飾變數的時候,意指系統總是重新從它所在的記憶體讀取資料。遇到這個關鍵字宣告的變 量,編譯器對訪問該變數的程式碼就不再進行優化,從而可以提供對特殊地址的穩定訪問。 舉一個容易理解的例子: volatile int i=10;
C語言之volatile關鍵字
volatile: volatile提醒編譯器它後面的定義隨時可能改變,因此編譯後的程式每次需要儲存或讀取這個變數時,都會直接從變數地址讀取資料。因此CPU訪問暫存器的速度要快過RAM,所以編譯器一般為了提高效率,會將變數放在暫存器中,通過訪問暫存器來讀取變數。但是這樣會造
C語言中關鍵字 volatile
1、volatile volatile關鍵字在c語言中用於表示變數是易變的,告訴編譯器不快取該變數,也就是每次訪問改變數都要去記憶體訪問,不會訪問該變數在快取中的副本,也就是CPU的一級二級三級等等快取,改變的時候也是直接寫回記憶體的,不會放到快取裡,一個定義為
C語言 volatile 和 restrict 關鍵字
(一) volatile 1、背景:關於編譯器的優化 線上程內, 當讀取一個變數時,為提高存取速度,編譯器優化時有時會先把變數讀取到一個暫存器中;以後再取變數值時,就直接從暫存器中取值;當變數值在本執行緒裡改變時,會同時把變數的新值copy到該暫存器中,以便保持一致。 當變數在因別的執行緒等
C++| |volatile關鍵字
volatile關鍵字 volatile的含義是“易變的”,含義是說這變數有可能會被意想不到的改變,這樣的話,編譯器就不會去假設這個變數的值,也就是不會為了優化到暫存器中讀取這個變數的值,會每次都到記憶體中讀取 是一個型別修飾符。 作用:
糾正網上一篇關於c++ volatile關鍵字的文章中的疏漏
前幾天無意中看到一篇文章,闡述c++ volatile關鍵字的作用。仔細看下來覺得一處內容有待商榷,而文章也是博主轉載的,既然找不到原作者,只能在此指出了。 首先,需要強調編譯器的版本,不同的編譯器有不同的優化方案,最終會影響生成的程式碼。本文使用vc++6
關於volatile關鍵字的用法,從彙編透視C語法操作
看一個簡單的c程式,p是沒加關鍵字volatile的int型指標,r是加關鍵字volatile的int型指標。 //main.c #include <stdio.h> void main(void) {int n;int *p;volatile int *r;
C/C++ volatile關鍵字
原文連結:https://blog.csdn.net/wwang196988/article/details/6623387 1. 為什麼用volatile? C/C++ 中的 volatile 關鍵字和 const 對應,用來修飾變數,通常用於建立語言
C語言中關鍵字auto、static、register、extern、volatile、restrict的作用
(1):auto關鍵字在C語言中只有一個作用,那就是修飾區域性變數。 (2):auto修飾區域性變數,表示這個區域性變數時自動區域性變數,自動區域性變數分配在棧上。(既然是分配在棧上,說明他如果不初始化的話那麼值就是隨機的....) (3):平時定義區域性變數時就是定義的auto的,只是省略了auto關鍵字
C++關鍵字的詳解 ---- volatile關鍵字
1.volatile的定義 volatile關鍵字是一種型別修飾符,用它宣告的型別變量表示可以被某些編譯器未知的因素更改,比如:作業系統、硬體或者其它執行緒等。由於訪問暫存器的速度要快過RAM,所以編譯器一般都會作減少存取外部RAM的優化。遇到這個關鍵字宣告的
C++中的volatile關鍵字
引子1 猜猜看,下面這段程式碼有什麼問題: ? 1 2 3 4 void Delay(UINT32 n) { while(—n); } 答案: 本來程式碼完全正常,但是為了優化效能,打開了編譯器的優化。但是發現這個函式被編
C++中有關volatile關鍵字的作用--阻止編譯器將其變數優化快取到暫存器(和執行緒相關)(轉自百度)
就象大家更熟悉的const一樣,volatile是一個型別修飾符(type specifier)。 它是被設計用來修飾被不同執行緒訪問和修改的變數 。 如果沒有volatile,基本上會導致這樣的結果:要麼無法編寫多執行緒