关于volatile关键字的说明以及测试(转载)

volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

使用该关键字的例子如下:

int volatile nVint;

  当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。

例如:

volatile int i=10;int a = i;...//其他代码,并未明确告诉编译器,对i进行过操作

int b = i;

  volatile 指出 i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是,由于编译器 发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者 表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问。
  注意,在vc6中,一般调试模式没有进行代码优化,所以这个关键字的作用看不出来。下面通过插入汇编代码,测试有无volatile关键字,对程序最终代码的影响:
  首先,用classwizard建一个win32 console工程,插入一个voltest.cpp文件,输入下面的代码:
 

#include void main(){    int i=10;    int a = i;

  printf("i= %d/n",a);   //下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道   __asm {       mov dword ptr [ebp-4], 20h    }

  int b = i;   printf("i= %d/n",b);}      

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

i = 10i = 32

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

i = 10i = 10

输出的结果明显表明,release模式下,编译器对代码进行了优化,第二次没有输出正确的i值。下面,我们把 i的声明加上volatile关键字,看看有什么变化:

#include void main(){    volatile int i=10;   int a = i;

  printf("i= %d/n",a);   __asm {       mov dword ptr [ebp-4], 20h    }

  int b = i;   printf("i= %d/n",b);}      

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

i = 10i = 32

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

C语言之static辨析(转载)- -

1、概述

  static 声明的变量在C语言中有两方面的特征:

  1)、变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。
 
  2)、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。

  2、问题:Static的理解

  关于static变量,请选择下面所有说法正确的内容:

  A、若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;

  B、若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;

  C、设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题;

  D、静态全局变量过大,可那会导致堆栈溢出。

  答案与分析:

  对于A,B:根据本篇概述部分的说明b),我们知道,A,B都是正确的。

  对于C:根据本篇概述部分的说明a),我们知道,C是正确的(所谓的函数重入问题,下面会详细阐述)。

  对于D:静态变量放在程序的全局数据区,而不是在堆栈中分配,所以不可能导致堆栈溢出,D是错误的。

  因此,答案是A、B、C。

  3、问题:不可重入函数

  曾经设计过如下一个函数,在代码检视的时候被提醒有bug,因为这个函数是不可重入的,为什么?

unsigned int sum_int( unsigned int base )
{
 unsigned int index;
 static unsigned int sum = 0; // 注意,是static类型的。
 for (index = 1; index <= base; index++)
 {
  sum += index;
 }
 return sum;
}

  答案与分析:

  所谓的函数是可重入的(也可以说是可预测的),即:只要输入数据相同就应产生相同的输出。

  这个函数之所以是不可预测的,就是因为函数中使用了static变量,因为static变量的特征,这样的函数被称为:带“内部存储器”功能的 的函数。因此如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量,这种函数中的static变量,使用原则是,能不用尽量不 用。

  将上面的函数修改为可重入的函数很简单,只要将声明sum变量中的static关键字去掉,变量sum即变为一个auto 类型的变量,函数即变为一个可重入的函数。

  当然,有些时候,在函数中是必须要使用static变量的,比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。

/**********************************************************************************************************/
这里是某论坛好人对volatile的一个简洁形象介绍:

其实Volatile是由于编译器优化所造成的一个Bug而引入的关键字。
int a = 10;
int b = a;
int c = a;
理论上来讲每次使用a的时候都应该从a的地址来读取变量值,但是这存在一个效率问题,就是每次使用a都要去内存中取变量值,然后再通过系统总线传 到CPU处理,这样开销会很大。所以那些编译器优化者故作聪明,把a读进CPU的cache里,像上面的代码,假如a在赋值期间没有被改变,就直接从 CPU的cache里取a的副本来进行赋值。但是bug也显而易见,当a在赋给b之后,可能a已经被另一个线程改变而重新写回了内存,但这个线程并不知 道,依旧按照原来的计划从CPU的cache里读a的副本进来赋值给c,结果不幸发生了。
于是编译器的开发者为了补救这一bug,提供了一个Volatile让开发人员为他们的过失埋单,或者说提供给开发人员了一个选择效率的权利。当变量加上了Volatile时,编译器就老老实实的每次都从内存中读取这个变量值,否则就还按照优化的方案从cache里读。

static和volatile的用法相关推荐

  1. java volatile实例_Java的Volatile实例用法及讲解

    Java的Volatile实例用法及讲解 发布时间:2020-10-03 12:01:58 来源:脚本之家 阅读:88 作者:konami 在原子性.可见性.有序性中,volatile关键字主要在可见 ...

  2. C#中static静态变量的用法

    原文:C#中static静态变量的用法 使用 static 修饰符声明属于类型本身而不是属于特定对象的静态成员static修饰符可用于类.字段.方法.属性.运算符.事件和构造函数,但不能用于索引器.析 ...

  3. static的三种用法,定义静态变量,静态函数,静态代码块!

    static的三种用法,定义静态变量,静态函数,静态代码块! 1.定义静态变量 class PersonStatic { //静态变量的特点 //1.静态变量无需生成对象就可被调用,可以使用类名和对象 ...

  4. Java中static的含义和用法

    Java中static的含义和用法 static:静态的,用于修饰成员(成员变量,成员方法); 1.被static所修饰的变量或者方法会储存在数据共享区; 2.被static修饰后的成员变量只有一份! ...

  5. public,static,private,protected的用法

    很多小伙伴不知道public,static,private,protected的用法,尤其是static和protected,虽然知道怎么用,但不知道是什么实际意义.小编这就为大家讲解! 在讲解之前, ...

  6. C语言中的关键字“ volatile”的用法(摘)

    C语言中的关键字" volatile"的用法(摘) volatile 这个ANSI C 关键字在经典的C 教程中很少提及,高层编程的人也可能永远都 不会用到,但是作为嵌入式开发者来 ...

  7. java $ 用法_Java的Volatile实例用法及讲解

    在原子性.可见性.有序性中,volatile关键字主要在可见性中发挥作用. volatile声明的变量对所有线程来说是可见的,就是说当变量的值发生改变的时候,其他线程可以立马发现这个变化. publi ...

  8. Java 中静态代码块 static的作用及用法

    java静态代码块的作用: Java静态代码块中的代码会在类加载JVM时运行,且只被执行一次,也就是说这些代码不需要实例化类就能够被调用.一般情况下,如果有些代码必须在项目启动的时候就执行的时候,就需 ...

  9. static、volatile、synchronize

    原子性(排他性):不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作! 可见性:多个线程对同一份数据操作,thread1改变了某个变量的值,要保证thread2能看见这个值被改变 ...

最新文章

  1. 有了这个Java项目经历,面大厂稳了!
  2. 安全编程: 防止缓冲区溢出
  3. 产生线程安全的原因(3)(操作系统)
  4. String中的compareTo()方法
  5. 最全的B端产品经理干货知识(3)
  6. Style transfer系列论文之——Arbitrary Style Transfer in Real-time with Adaptive Instance Normali,ICCV, 2017
  7. Regularized logistic regression(正则化逻辑回归)----吴恩达机器学习
  8. 温故知新(七七)nextTick 是在本次循环执行,还是在下次,setTimeout(()=>{},0)呢
  9. Java支付宝订单查询
  10. vue中过滤器大全(一)【两位小数、银行卡号】
  11. python之global关键字
  12. 超说网络NO.4 | 深入了解应用层原理(中科大 郑烇)
  13. [2017.02.06] 阅读《Effective Morden C++》
  14. BIOS实战之读写逻辑设备(SIO)
  15. 实体零售关店潮之下 这个美国品牌偏不信邪
  16. 影音推荐 | 开源界的演讲和纪录片了解一下
  17. 在公路项目里路缘石滑模机施工作业需要注意这些
  18. Android 真机调试
  19. Excel中的数据有效性
  20. 自学Java如何快速的找到工作?

热门文章

  1. Spark学习(一)—— 论文翻译
  2. MySQL数据库-详解
  3. 一文了解什么是ERP!文末有免费数字化转型资料赠送
  4. 第2章【思考与练习3】随机游走轨迹模拟。将随机游走的步数增加到100步,计算物体最终与原点的距离。重复多次随机游走过程,观察物体与原点距离的变化趋势。
  5. 最给力的营销技巧 让消费者自己改变主意
  6. 当HUAWEI HiAI遇到淘宝
  7. 宝塔7Linux去掉文件夹的锁
  8. C++读取和写入文件 Mark !! 汉字转拼音 带声调!
  9. .Net轻松处理亿级数据--clickhouse及可视化界面安装介绍
  10. image+animaton