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是立即数,也称为右值,无法赋值的!立即数就如c语言中的常量

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

 volatile *(unsigned int*)(BLOCK_2_APB2_GPIO_B+0x0)
预编译后:

volatile *(unsigned int*)(0x100+0x0) |= 1
这样编译器就会把0x100+0x0的地址里的值|=1

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

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

转载于:https://blog.csdn.net/bjbz_cxy/article/details/80438354

猜你喜欢

转载自blog.csdn.net/qq_38531460/article/details/106625379
今日推荐