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
如果数组类型使用 volatile 类型限定符声明(通过使用 |
(直到 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
如果函数类型使用 volatile 类型限定声明(通过使用 typedef
),则行为未定义。
在函数声明中,关键字 以下两个声明声明了相同的函数 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 ) 类型限定符 |