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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章