C
C 语法

volatile type qualifier

volatile type qualifier

C类型系统中的每个单独类型都具有该类型的多个限定版本,对应于const,volatile中的一个,两个或全部三个,并且对于指向对象类型的指针,限制限定符。该页面描述了volatile限定符的影响。

通过volatile限定类型的左值表达式进行的每次访问(包括读取和写入)都被认为是可观察的副作用,并且严格按照抽象机器的规则进行评估(即,所有写入均在在下一个序列点之前的某个时间)。这意味着在单个执行线程中,相对于由易失性访问序列点分隔的另一个可见副作用,无法优化或重新排序易失性访问。

将非易失性值转换为易失性类型不起作用。要使用易失性语义访问非易失性对象,必须将其地址强制转换为易失性指针,然后必须通过该指针进行访问。

任何尝试读取或写入类型为volatile的对象 - 通过非易失性左值限定会导致未定义的行为:

volatile int n = 1; // object of volatile-qualified type int* p = (int*)&n; int val = *p; // undefined behavior

一个挥发性限定结构或联合类型的成员获取它所属类型的限定条件(在使用.操作员或->操作员进行访问时):

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类型限定符(通过使用typedef)声明数组类型,则数组类型不是volatile限定的,但其元素类型为。如果一个函数类型被声明为具有限定的volatile类型(通过使用typedef),则行为是未定义的。

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*

在函数声明中,关键字volatile可能出现在用于声明函数参数数组类型的方括号内。它限定了数组类型被转换的指针类型。以下两个声明声明了相同的函数:void f(double xvolatile,const double yvolatile); void f(double * volatile x,const double * volatile y);(自C99以来)

指向非易失性类型的指针可以隐式转换为指向相同或兼容类型的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)

易变的用途

1)静态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

2)static volatile类型的对象sig_atomic_t用于与signal处理程序进行通信。

3)volatile包含setjmp宏调用的函数的局部变量是保证在longjmp返回后保留其值的唯一局部变量。

4)此外,可以使用volatile变量来禁用某些形式的优化,例如,禁用dead store消除或对microbenchmarks进行常量折叠。

请注意,volatile变量不适合线程之间的通信; 他们不提供原子性,同步或内存排序。从另一个线程修改的易失性变量中读取来自两个未同步的线程的同步或并发修改是由于数据竞争造成的未定义行为。

关键词

volatile.

演示了如何使用volatile来禁用优化。

#include <stdio.h> #include <time.h> int main(void) { clock_t t = clock( double d; for (int n=0; n<10000; ++n) for (int m=0; m<10000; ++m) d += d*n*m; // reads 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; for (int n=0; n<10000; ++n) for (int m=0; m<10000; ++m) vd += vd*n*m; // reads 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

参考

  • C11标准(ISO / IEC 9899:2011):