首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

volatile type qualifier

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

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

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

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

代码语言:javascript
复制
volatile int n = 1; // object of volatile-qualified type
int* p = (int*)&n;
int val = *p; // undefined behavior

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

代码语言:javascript
复制
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),则行为是未定义的。

代码语言:javascript
复制
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限定版本的指针。逆转换可以使用强制表达式来执行。

代码语言:javascript
复制
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; 对于两种类型的兼容,其资格必须相同:

代码语言:javascript
复制
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对象模型存储器映射的输入端口,例如实时时钟:

代码语言:javascript
复制
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来禁用优化。

代码语言:javascript
复制
#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);
}

可能的输出:

代码语言:javascript
复制
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):
    • 6.7.3类型限定符(p:121-123)
  • C99标准(ISO / IEC 9899:1999):
    • 6.7.3类型限定符(p:108-110)
  • C89 / C90标准(ISO / IEC 9899:1990):
    • 3.5.3类型限定符

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com