C语言中volatile关键字的作用及说明

 更新时间:2024年10月29日 14:31:05   作者:莱特昂  
文中主要介绍了C语言中volatile关键字的含义和使用场景,volatile是一个类型修饰符,主要用来修饰被不同线程访问和修改的变量,它的作用是防止编译器对代码进行优化,确保每次直接读取原始内存地址的值

volatile关键字的作用

在看C语言基础知识的时候看到了volatile关键字,不是很理解,所以查了资料,总结一下。

volatile译为:易变的

  • volatile是一个类型修饰符(type specifier),就像我们熟悉的const一样,它是被设计用来修饰被不同线程访问和修改的变量;
  • volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。

简单地说就是防止编译器对代码进行优化。

比如如下程序:

XBYTE[2]=0x55;
XBYTE[2]=0x56;
XBYTE[2]=0x57;
XBYTE[2]=0x58;

对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器却会对上述四条语句进行优化,认为只有XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。

如果键入volatile,则编译器会逐一地进行编译并产生相应的机器代码(产生四条代码)。

典型的例子

for(int i=0; i<100000; i++);

这个语句用来测试空循环的速度的

但是编译器肯定要把它优化掉,根本就不执行

如果你写成

for(volatile int i=0; i<100000; i++);

它就会执行了

volatile的本意是“易变的”

下面是volatile变量的几个例子:

1)并行设备的硬件寄存器(如:状态寄存器)

2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

3)多线程应用中被几个任务共享的变量

一些相关的面试题

1)一个参数既可以是const还可以是volatile吗?解释为什么。

2)一个指针可以是volatile 吗?解释为什么。

3)下面的函数被用来计算某个整数的平方,它能实现预期设计目标吗?如果不能,试回答存在什么问题:

int square(volatile int *ptr)
{
   return ((*ptr) * (*ptr));
}

下面是答案:

1)是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。

2)是的。尽管这并不很常见。一个例子是当一个中断服务子程序修改一个指向一个buffer的指针时。

3)这段代码是个恶作剧。这段代码的目的是用来返指针ptr指向值的平方,但是,由于ptr指向一个volatile型参数,编译器将产生类似下面的代码:

int square(volatile int* &ptr)//这里参数应该申明为引用,不然函数体里只会使用副本,外部没法更改

{
    int a,b;
    a = *ptr;
    b = *ptr;
    return a*b;
}

由于ptr的值可能在两次取值语句之间发生改变,因此a和b可能是不同的。

结果,这段代码可能返回的不是你所期望的平方值!

正确的代码如下:

long square(volatile intptr)
{
    int a;
    a = *ptr;
    return a*a;
}

另外,还可能出现在debug版中看不出来,在release版中才显现的问题:

#include<stdio.h>
void main(int argc,char *argv[])
{
 int i = 10;
 int a = i;
 printf("i=%d",a);
 //下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道
__asm
    {
        mov dword ptr[ebp-4],20h
    }
    int b = i;
    printf("i=%d",b);
}

然后,在调试版本模式运行程序,输出结果如下:

i = 10
i = 32

然后,在release版本模式运行程序,输出结果如下:

i = 10
i = 10

输出的结果明显表明,release模式下,编译器对代码进行了优化,第二次没有输出正确的i值。

我们把 i的声明加上volatile关键字,看看有什么变化:

#include<stdio.h>
void main(int argc,char *argv[])
{
    volatile int i = 10;
    int a = i;
    printf("i=%d",a);
    __asm
    {
    `    mov dword ptr[ebp-4],20h
    }
    int b = i;
    printf("i=%d",b);
}

分别在调试版本和release版本运行程序,输出都是:

i = 10
i = 32

这说明这个关键字发挥了它的作用!

volatile应该解释为“直接存取原始内存地址”比较合适,“易变的”这种解释简直有点误导人;

比如多线程的程序,共同访问的内存当中,多个程序都可以操纵这个变量

你自己的程序,是无法判定何时这个变量会发生变化

还比如,他和一个外部设备的某个状态对应,当外部设备发生操作的时候,通过驱动程序和中断事件,系统改变了这个变量的数值,而你的程序并不知道。

对于volatile类型的变量,系统每次用到他的时候都是直接从对应的内存当中提取,而不会利用cache当中的原有数值,以适应它的未知何时会发生的变化,系统对这种变量的处理不会做优化——显然也是因为它的数值随时都可能变化的情况。

使用地方

一般说来,volatile用在如下的几个地方:

1、中断服务程序中修改的供其它程序检测的变量需要加volatile;

2、多任务环境下各任务间共享的标志应该加volatile;

3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义;

另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实现,2 中可以禁止任务调度,3中则只能依靠硬件的良好设计了。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • C语言内存函数的具体使用

    C语言内存函数的具体使用

    本文介绍了C语言中几个常用的内存函数,包括memcpy、memmove、memset、memcmp的使用方法及其模拟实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-11-11
  • 一文详解QDialog中exec与open的区别

    一文详解QDialog中exec与open的区别

    这篇文章主要为大家详细介绍了QDialog中exec与open的区别,文中的示例代码讲解详细,对我们学习Qt有一定的帮助,需要的可以参考一下
    2023-03-03
  • C语言中char*和char[]用法区别分析

    C语言中char*和char[]用法区别分析

    这篇文章主要介绍了C语言中char*和char[]用法区别,包括使用过程中的误区及注意点分析,需要的朋友可以参考下
    2014-09-09
  • C语言文件操作实现数据持久化(帮你快速了解文件操作函数)

    C语言文件操作实现数据持久化(帮你快速了解文件操作函数)

    持久数据其实就是将数据保存到数据库,下面这篇文章主要给大家介绍了关于C语言文件操作实现数据持久化(帮你快速了解文件操作函数)的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • C++ sort排序函数用法详解

    C++ sort排序函数用法详解

    本文主要介绍了C++ sort排序函数用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • 基于重启后消失的注册表键值的详细介绍

    基于重启后消失的注册表键值的详细介绍

    本篇文章是对重启后消失的注册表键值进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • Qt Designer的简单使用方法

    Qt Designer的简单使用方法

    用 C++ 代码编写图形界面的问题就是不直观,因此 Qt 项目开发了专门的可视化图形界面编辑器,本文就详细的介绍一下
    2021-08-08
  • do...while(0)的妙用详细解析

    do...while(0)的妙用详细解析

    do...while(0)消除goto语句;通常,如果在一个函数中开始要分配一些资源,然后在中途执行过程中如果遇到错误则退出函数,当然,退出前先释放资源
    2013-09-09
  • C++操作json文件以及jsoncpp配置详解

    C++操作json文件以及jsoncpp配置详解

    这篇文章主要给大家介绍了关于C++操作json文件以及jsoncpp配置的相关资料,文中通过实例代码及图片介绍的非常详细,需要的朋友可以参考下
    2021-06-06
  • C++(STL库)之顺序容器vector的使用

    C++(STL库)之顺序容器vector的使用

    这篇文章主要介绍了C++(STL库)之顺序容器vector的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02

最新评论