`
rommal7090
  • 浏览: 107511 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
阅读更多

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可以保证对特殊地址的稳定访问。

####################典型问题######################

关键字volatile有什么含意?并给出三个不同的例子。

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
1).
并行设备的硬件寄存器(如:状态寄存器)
2).
一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3).
多线程应用中被几个任务共享的变量
回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。
假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。
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的值可能被意想不到地该变,因此ab可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}

************************补充*******************************

volatile的本意是易变的由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。比如:

static int i=0;

int main(void)
{
...
while (1)
{
if (i) dosomething();
}
}

/* Interrupt service routine. */
void ISR_2(void)
{
i=1;
}

程序的本意是希望ISR_2中断产生时,在main当中调用dosomething函数,但是,由于编译器判断在main函数里面没有修改过i,因此可能只执行一次对从i到某寄存器的读操作,然后每次if判断都只使用这个寄存器里面的“i副本,导致dosomething永远也不会被调用。如果将将变量加上volatile修饰,则编译器保证对此变量的读写操作都不会被优化(肯定执行)。此例中i也应该如此说明。

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

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

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

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

volatile表示变量的内容可能在程序未知的情况下被改变
比如,它对应的内存地址的内容被中断函数,或者其他的进程所改变
这种类型的变量,程序执行的时候不会放到cache当中预取,而是每次用到的时候直接取得
比如,你在c中间写这样的程序
for (int i=0; i<100000;i++);
空循环,什么也不做
这个东西就会被优化调,如果在int前面加入这个标记则不会被优化的,因为i每次的变化不一定++也虚在循环中间被别的程序所改变

linuxsource codelinux/mm/memory.c)中有这样两句:
volatile void do_exit(long code);

static inline volatile void oom(void)
{
printk("out of memory\n\r");
do_exit(SIGSEGV);
}

分享到:
评论

相关推荐

    单片机C语言中volatile的作用

    ### 单片机C语言中volatile的作用 在探讨单片机C语言中`volatile`关键字的作用之前,我们首先需要理解`volatile`的基本概念及其应用场景。`volatile`是一个用于声明变量的关键字,在C语言中,使用`volatile`修饰的...

    C语言中关于关键字volatile的用法

    这就解释了为什么在计算指针所指向数据的平方时,不能简单地假设指针指向的数据在两次读取间不会改变。正确的代码应该确保在每次操作前重新读取数据,避免因数据变化导致的计算错误。 综上所述,volatile关键字在...

    mcu-volatile-example.rar_volatile_单片机C语言

    这意味着学习者可以通过阅读代码和注释,了解 `volatile` 在实际编程中的用法,并且有文字解释可以帮助理解其背后的理论。这对于初学者来说是非常宝贵的资源,因为理论与实践相结合的学习方式往往能更有效地掌握知识...

    初见volatile.md,学习代码

    压缩包内的“JUC-ThreadLocal内存泄漏弱引用.png”和“JUC-ThreadLocal内存泄漏强引用.png”可能是对这种问题的视觉解释。 最后,了解并发编程不仅需要掌握`volatile`、`ThreadLocal`等基础概念,还需要理解Java...

    Volatile.pdf

    文档还提到了一些与volatile关键字紧密相关的概念,如内存可见性、指令重排序、Java内存模型(JMM)等。内存可见性指的是当一个线程修改了共享变量的值,其他线程能够立即看到该变量的最新值。指令重排序是指编译器...

    【C语言】Volatile的陷阱

    本文将从 volatile 关键字的使用陷阱和注意事项入手,详细解释 volatile 关键字的使用方法和注意事项,以避免在嵌入式开发中遇到的问题。 volatile 关键字的使用注意事项 volatile 关键字是一种特殊的修饰符,用于...

    Java并发编程(18)第五篇中volatile意外问题的

    总之,"Java并发编程(18)第五篇中volatile意外问题的正确分析解答"这篇文档深入浅出地解释了volatile的关键特性,揭示了其在并发编程中的局限性,并给出了实际问题的解决方案,对于提升Java并发编程能力具有很高的...

    C语言中关键字const、static、volatile、extern、auto、register的用法分析.doc

    本文将对C语言中的六个关键字:const、static、volatile、extern、auto、register进行详细的分析和解释。 一、const关键字 Const关键字是C语言中最基本的关键字之一,它的主要作用是将变量或对象声明为只读的,...

    volatile关键字 Const关键字 static关键字 mutable 关键字

    下面将详细解释这些关键字的作用以及它们在程序设计中的应用。 1. `volatile` 关键字 `volatile` 用于标记一个变量,表明它的值可能会在编译器无法察觉的情况下发生变化。这通常发生在多线程环境、硬件交互或中断...

    C++中volatile关键字及常见的误解总结

    网上也看到很多关于volatile的误解,于是决定写这篇文章详细解释一下volatile的作用到底是什么。 为什么用volatile? C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的 memory ...

    java volatile关键字作用及使用场景详解

    下面将详细解释`volatile`的关键特性、它如何解决并发问题以及相关的`happens-before`原则。 1. **可见性**: `volatile`关键字确保了被其修饰的变量在所有线程之间具有可见性。这意味着当一个线程修改了`volatile...

    java代码-volatile原子性

    而`README.txt`文件可能是对代码的解释或使用说明。 总的来说,`volatile`关键字在Java中用于解决多线程环境下的可见性和有序性问题,但不能保证原子性。在编写多线程程序时,我们需要结合使用`volatile`、`...

    通过volatile验证线程之间的可见性

    本篇文章将深入探讨如何通过`volatile`关键字验证线程之间的可见性,并通过示例代码详细解释其工作原理。 首先,我们需要理解Java内存模型(JMM)。在JMM中,存在两种内存区域:主内存和工作内存。主内存是所有线程...

    C++中volatile关键字的使用详解以及常见的误解

    在"The C++ Programming Language"一书中,Bjarne Stroustrup解释了`volatile`的作用:它是一种编译器提示,告诉编译器对象的值可能以语言本身无法确定的方式发生改变,因此应避免执行可能导致错误优化的步骤。...

    C语言中const,volatile,restrict的用法总结

    以下是对这三个关键字的详细解释: 1. `const` 关键字: `const`用于声明常量,它表明变量的值不应该被程序更改。在声明常量变量时,一旦赋值后就不能再通过赋值、增加或减少操作改变其值。对于指针,`const`可以...

    电子-stm32库函数解释.doc

    STM32库函数解释 STM32库函数解释是一份关于单片机/嵌入式STM32-F0/F1/F2的库函数手册,提供了对应的库函数解释和使用说明。本手册共分为八大类,每类对应一个STM32单片机的外设,分别是通用输入/输出(GPIO)、...

    Java试题笔试题目答案.docx

    本文将深入探讨Java中`volatile`关键字的相关知识点,以及其在多线程环境中的作用。 1) `volatile`关键字允许创建可变的共享变量,确保了线程间的可见性。在Java中,`volatile`数组只是指向数组的引用是`volatile`...

    c语言语句声明 解释程序

    1. **类型修饰符**:如`const`、`volatile`等,它们可以修饰变量或函数,改变其行为。 2. **指针**:C语言中的指针是内存地址的别名,可以用于间接访问数据。 3. **数组**:数组是一组相同类型的元素集合,可以通过...

Global site tag (gtag.js) - Google Analytics