volatile讲解与宏定义

在嵌入式面试时volatile是必考题!

下面来解释一下volatile关键字的作用:

volatile关键字,是用于表明变量代码无法被优化!

比如:

int a = 0;
a = 1;
a = 2;
a = 3;

经过编译器代码优化后:

int a = 0;
a = 3;

省去重复工作,debug下不会作任何优化,但这样的代码效率一般只用在调试下,release模式下会对齐进行优化,在GCC的编译器下会直接对这段代码优化,GCC下没有debug和release模式!

这样的情况对,应用层来说可以解决重复代码,有效提高编码以及运行效率!

但是对于嵌入式开发就不一样了,每个电平对于不同的情况

GPIO_C |= (1<<5);   
sleep(0xFFFFF);
GPIO_C |= (0<<5);

这段代码是让LED灯闪烁,但是倘若编译器为其进行了优化就会变成:

sleep(0xFFFFF);
GPIO_C |= (0<<5);

看不到闪烁的情况了,因为编译器觉得GPIO_C最终的结果会是 |= 0<<5,所以直接索性优化掉上面重复代码!

这样的话GPIO_C端口就接受不到高电平,也就无法驱动LED灯亮起,所以这样做是不对的!

所以我们要用到volatile关键,告诉编译器,无论如何都不要尝试对被volatile关键字声明的变量进行优化!

这样的话编译器就不会对齐变量进行优化!

volatile int a = 0;

即使是宏的情况下,编译器也一样会对其进行优化,所以我们要在宏定义里也加上volatile:

#define volatile  *(unsigned int*) 0x410000

这里在说说宏定义:

#define BLOCK_2_GPIOB_CRL      volatile  *(unsigned int*)BLOCK_2_APB2_GPIO_B+0x0    //BLOCK_2_APB2_GPIO_B = 0X100

在运用时

BLOCK_2_GPIOB_CRL |= 1

编译时会出现错误:表达式必须为左值

其实原因很简单,下面给大家看一下预编译文件:

volatile *(unsigned int*)0x100+0x0 |= 1

后面的0x100+0x0就错了!

编译器看成先对0x100地址取值,然后在加上0x0|=1

这样显然是错误的,0x0是立即数,也称为右值,无法赋值的!

所以我们要加上括号增加运算符优先级

 volatile *(unsigned int*)(BLOCK_2_APB2_GPIO_B+0x0)

预编译后:

volatile *(unsigned int*)(0x100+0x0) |= 1

这样编译器就会把0x100+0x0的地址里的值|=1

也就是将0x100这块内存地址的值赋予新的值,新值是0x100里的值|=1

因为上面用了赋值运算符=

猜你喜欢

转载自blog.csdn.net/bjbz_cxy/article/details/80438354