C语言volatile修饰符

时间:2021-05-01 21:06:20

volatile:作为指令关键字,确保本条指令不会被编译器优化而被省略,要求每次都读值,例:

1

2

3

4

XBYTE[2]=0x55;

XBYTE[2]=0x56;

XBYTE[2]=0x57;

XBYTE[2]=0x58;

      编译器会优化,只操作最后的XBYTE[2]=0x58;但是对外部硬件来说这是4个操作,被优化了就会导致硬

件流程出现问题,只产生了一个机器码,因此需要加volatile修饰符。

    一个变量被定义为volatile意思是这个变量可能会被意想不到的改变,读值保证了可以响应修改,不会

出现修改了但是读的还是之前的值的情况。修饰后编译器不能假设这个变量的值,只能每次都读取这个变量的

值,而不是寄存器中存着的。必须使用volatile的场合:

    1.并行设备的硬件寄存器,比如状态寄存器

    2.一个中断服务子程序可能访问的非自动变量

    3.多线程应用中被几个程序共享的变量

    注意的点:

    1.一个参数可以既是const又是volatile,volatile保证被意外修改仍能读取到最新的值,const保证

不应该被修改

    2.指针可以是volatile,例如中断服务子程序修改一个指向buffer的指针

    编译器优化:在一个线程内,读取一个变量时,为了提高读取速度,编译器会把变量值放到内存中,以后

再读取时,直接从内存中读取。本线程内若改变变量值,会把新的值copy到寄存器,保持一致。别的线程改了

这个变量的值,寄存器值不变就会出问题。别的线程改了寄存器的值,变量值没变,就会出问题。

    在debug版本,不会优化,在release版本,会被优化,所以release版本需要额外注意,内嵌汇编方法

#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);

}

 

    这个例子

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

static int i = 0;

int main(void)

{

    //...

    while(1)

    {

        if(i)

            dosomething();

    }

}

/*Interruptserviceroutine.*/

void ISR_2(void)

{

    i=1;

}

 

    本意是希望中断后i = 1,main函数响应,但是编译器判断main中没有修改i的值,因此可能只执行一次

从i到寄存器的读操作,然后每次判断都从寄存器中取副本,导致中断永远不会被响应,此时需要加volatile

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