c代码中volatile关键字的作用,除了阻止cpu直接使用寄存器和cache中变量,还有其他功能吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c代码中volatile关键字的作用,除了阻止cpu直接使用寄存器和cache中变量,还有其他功能吗?相关的知识,希望对你有一定的参考价值。

如题

参考技术A 面试题里面会问到的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的值可能被意想不到地改变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)

int a;
a = *ptr;
return a * a;
参考技术B 就是为了避免非预期的被更改 参考技术C volatile表明该变量可能在其它代码中被修改,以免编译器在优化时出现错误。
比如以下程序:
int x, y;
x = 5;
y = x + 1;
只看这段代码,在编译优化时,完全可以把y = x + 1 直接编译成 y=6 而得到完全正确的结果。
如果把x声明为 volatile int x; 编译器就不会做这种猜测性的优化,而直接使用x的现有值。

声明为volatile,只有该变量在其它模块中可能被修改的情况下才有意义,否则只会阻止对该变量进行的编译优化,降低编译效率。对于auto类型、static类型的变量,显然没必要声明为volatile的。
可以说,只有可能在其它模块中被修改的全局符号,只有在编写并发程序时,才可能出现使用volatile的必要性。本回答被提问者和网友采纳

C语言 volatile 关键字在编译优化过程中有何作用


来自公众号:strongerHuang

初学的读者可能不怎么关心编译器优化的功能,但对于经验丰富的工程师来说,掌握代码优化是必备技能。


今天讲述的话题就是关于代码优化中,关键字volatile在优化过程中起到的作用。


一、关键字 volatile 什么?

volatile是一个类型修饰符(type specifier)。 


volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。


volatile变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。


---来自百度百科

volatile的定义,应该在(读书)学习时都看过无数遍,但我相信绝大部分人都没有深刻理解其中含义。


当你真正编程、开发项目之后,你就会进一步理解其中含义。


二、volatile关键字对编译器优化的影响

我们都知道编译器有优化代码的功能,我们常用的集成开发环境(Keil、 IAR等)都有优化选项。


如果不使用关键字 volatile 申明变量,则编译器可能会对变量的访问并生成非预期的代码或删除预期的功能。


1.何时使用volatile?

常见使用volatile声明的情况:

  • 访问内存映射外设。

  • 在多个线程之间共享全局变量。

  • 在中断例程或信号处理程序中访问全局变量。


比如,在STM32代码中:

#define __O volatile /*!< Defines 'write only' permissions */#define     __IO    volatile             /*!< Defines 'read / write' permissions */

浏览代码,你会发现,很多地方都使用了“__IO”,也就是volatile.


在跑系统的项目中,线程间共享的全局变量,建议都加上volatile关键字,这一点,很多人没有在意。


2.不使用volatile时可能出现的问题

如果未将变量用volatile声明,则编译器会假定其值不能在其定义的范围之外进行修改。


因此,编译器可能会执行不需要的优化。这可以通过多种方式表现出来:

  • 在轮询硬件时,代码可能会陷入循环。

  • 多线程代码可能会表现出奇怪的行为。

  • 优化可能会导致删除实现故意时序延迟的代码。


举例:

自己写一个延时函数:

void Delay(int Cnt){ int i;
while(Cnt--) { i++; for(i=0; i<10; i++); }}


你在不同优化等级情况下,延时时间可能会不一样;


同样的代码,你在Keil 和 IAR环境下编译出来的延时时间也可能不一样。


当然,更深入的理解就会牵涉到汇编代码,编译之后的汇编代码会比较直观的呈现差异。


●输入m获取文章

C语言与C++编程

分享C/C++技术文章

以上是关于c代码中volatile关键字的作用,除了阻止cpu直接使用寄存器和cache中变量,还有其他功能吗?的主要内容,如果未能解决你的问题,请参考以下文章

C语言 中volatile关键字的用法

C/C++面试必备详解C/C++中volatile关键字

static和volatile都有哪些用途用途。

java并发之volatile关键字

Java中关键字volatile 和 synchronized 的作用和区别

(C)volatile关键字