volatile 型別限定符
C 型別系統中的每個單獨型別都有其幾種限定版本,對應於一個、兩個或全部三個限定符:const
、volatile
,以及對於指向物件型別的指標,restrict
。本頁描述了 volatile
限定符的效果。
透過 volatile 限定型別左值表示式進行的每次訪問(讀和寫)都被視為最佳化的可觀察副作用,並嚴格按照抽象機器的規則進行評估(即,所有寫入都在下一個序列點之前的某個時間完成)。這意味著在單個執行執行緒中,volatile 訪問不能被最佳化掉,也不能相對於與 volatile 訪問透過序列點分離的另一個可見副作用進行重新排序。
將非 volatile 值強制轉換為 volatile 型別沒有效果。要使用 volatile 語義訪問非 volatile 物件,必須將其地址強制轉換為指向 volatile 的指標,然後透過該指標進行訪問。
任何透過非 volatile 左值讀寫 volatile 限定型別的物件的嘗試都會導致未定義行為。
volatile int n = 1; // object of volatile-qualified type int* p = (int*)&n; int val = *p; // undefined behavior
volatile 限定結構或聯合型別的成員會獲得其所屬型別的限定(無論是使用 .
運算子還是 ->
運算子訪問)。
struct s { int i; const int ci; } s; // the type of s.i is int, the type of s.ci is const int volatile struct s vs; // the types of vs.i and vs.ci are volatile int and const volatile int
如果陣列型別透過使用 |
(直至 C23) |
陣列型別及其元素型別始終被認為是具有相同 volatile 限定的。 |
(自 C23 起) |
typedef int A[2][3]; volatile A a = {{4, 5, 6}, {7, 8, 9}}; // array of array of volatile int int* pi = a[0]; // Error: a[0] has type volatile int* void *unqual_ptr = a; // OK until C23; error since C23 // Notes: clang applies the rule in C++/C23 even in C89-C17 modes
如果函式型別透過使用 typedef
宣告為 volatile 型別限定符,則行為是未定義的。
在函式宣告中,關鍵字 以下兩個宣告聲明瞭相同的函式 void f(double x[volatile], const double y[volatile]); void f(double * volatile x, const double * volatile y); |
(C99 起) |
指向非 volatile 型別的指標可以隱式轉換為指向相同或相容型別的 volatile 限定版本的指標。反向轉換需要強制轉換表示式。
int* p = 0; volatile int* vp = p; // OK: adds qualifiers (int to volatile int) p = vp; // Error: discards qualifiers (volatile int to int) p = (int*)vp; // OK: cast
注意,指向 T
的指標不能轉換為指向 volatile T
的指標;對於兩種型別要相容,它們的限定必須相同。
char *p = 0; volatile char **vpp = &p; // Error: char* and volatile char* are not compatible types char * volatile *pvp = &p; // OK, adds qualifiers (char* to char*volatile)
目錄 |
[編輯] volatile 的用途
static
volatile
物件模擬記憶體對映 I/O 埠,而 static
const
volatile
物件模擬記憶體對映輸入埠,例如即時時鐘。volatile short *ttyport = (volatile short*)TTYPORT_ADDR; for(int i = 0; i < N; ++i) *ttyport = a[i]; // *ttyport is an lvalue of type volatile short
注意,volatile 變數不適合執行緒間通訊;它們不提供原子性、同步或記憶體排序。在沒有同步的情況下,從一個被另一個執行緒修改的 volatile 變數中讀取,或者來自兩個未同步執行緒的併發修改,由於資料競爭而導致未定義行為。
[編輯] 關鍵詞
[編輯] 示例
演示了使用 volatile 停用最佳化
#include <stdio.h> #include <time.h> int main(void) { clock_t t = clock(); double d = 0.0; for (int n = 0; n < 10000; ++n) for (int m = 0; m < 10000; ++m) d += d * n * m; // reads from and writes to a non-volatile printf("Modified a non-volatile variable 100m times. " "Time used: %.2f seconds\n", (double)(clock() - t)/CLOCKS_PER_SEC); t = clock(); volatile double vd = 0.0; for (int n = 0; n < 10000; ++n) for (int m = 0; m < 10000; ++m) { double prod = vd * n * m; // reads from a volatile vd += prod; // reads from and writes to a volatile } printf("Modified a volatile variable 100m times. " "Time used: %.2f seconds\n", (double)(clock() - t)/CLOCKS_PER_SEC); }
可能的輸出
Modified a non-volatile variable 100m times. Time used: 0.00 seconds Modified a volatile variable 100m times. Time used: 0.79 seconds
[編輯] 參考文獻
- C17 標準 (ISO/IEC 9899:2018)
- 6.7.3 型別限定符 (p: 87-90)
- C11 標準 (ISO/IEC 9899:2011)
- 6.7.3 型別限定符 (p: 121-123)
- C99 標準 (ISO/IEC 9899:1999)
- 6.7.3 型別限定符 (p: 108-110)
- C89/C90 標準 (ISO/IEC 9899:1990)
- 6.5.3 型別限定符
[編輯] 另請參閱
C++ 文件,關於cv (
const 和 volatile ) 型別限定符 |