在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

那些書本上都沒有提到的C語言volatile用法

STM32嵌入式開發 ? 來源:嵌入式ARM ? 作者:嵌入式ARM ? 2021-10-12 14:47 ? 次閱讀

許多程序員都無法正確理解C語言關鍵字volatile,這并不奇怪。因為大多數C語言書籍通常都是一兩句一帶而過,本文將告訴你如何正確使用它。

在C/C++嵌入式代碼中,你是否經歷過以下情況:

代碼執行正常–直到你打開了編譯器優化

代碼執行正常–直到打開了中斷

古怪的硬件驅動

RTOS的任務獨立運行正常–直到生成了其他任務

如果你的回答是“yes”,很有可能你沒有使用C語言關鍵字volatile。你并不是唯一的,很多程序員都不能正確使用volatile。不幸的是,大多數c語言書籍對volatile的藐視,只是簡單地一帶而過。

volatile用于聲明變量時的使用的限定符。它告訴編譯器該變量值可能隨時發生變化,且這種變化并不是代碼引起的。給編譯器這個暗示是很重要的。在開始前,我們向來看一看volatile的語法。

C語言關鍵字volatile語法

聲明一個變量為volatile,可以在數據類型之前或之后加上關鍵字volatile。下面的語句,把foo聲明一個volatile的整型。

volatile int foo;int volatile foo;

把指針指向的變量聲明為volatile很常見,尤其是I/O寄存器的地址映射。下面的語句,把pReg聲明為一個指向8-bit無符號指針,指針指向的內容為volatile。

volatile uint8_t * pReg;uint8_t volatile * pReg;

volatile的指針指向非volatile的變量很少見(我只使用過一次),但我還是給出相應的語法。

int * volatile p;

順便提一下,關于為什么要在數據類型前使用volatile關鍵字,請自行百度搜素。

最后,如果你再struct或者union前使用volatile關鍵字,表明struct或者union的所有內容都是volatile。如果這不是你的本意,可以在struct或者union成員上使用volatile關鍵字。

正確使用C語言關鍵字volatile

只要變量可能被意外的修改,就需要把該變量聲明為volatile。在實際應用中,只有三種類型數據可能被修改:

外設寄存器地址映射

在中斷服務程序中修改全局變量

在多線程、多任務應用中,全局變量被多個任務讀寫

接下來,我們將分別討論上述三種情況。

外設寄存器

嵌入式系統包含真正的硬件,通常會有復雜的外設。這些外設寄存器的值可能被異步的修改。舉個簡單的例子,我們要把一個8-bit狀態寄存器的地址映射到0x1234。在程序中循環查看該狀態寄存器的值是否變為非0。C語言操作寄存器的手法,可以參考這篇文章:C語言操作寄存器的常見手法。

下面是最容易想到,但錯誤的實現方法:

bdfdf05a-2b08-11ec-82a8-dac502259ad0.png

當你打開編譯器優化時,程序總是執行失敗。因為編譯器會生成下面的匯編代碼:

be3e0974-2b08-11ec-82a8-dac502259ad0.png

程序被優化的原因很簡單,既然已經把變量的值讀入累加器,就沒有必要重新一遍,編譯器認為值是不會變化的。就這樣,在第三行,程序進入了無限死循環。為了告訴編譯器我們的真正意圖,我們需要修改函數的聲明:

be89177a-2b08-11ec-82a8-dac502259ad0.png

編譯器生成的匯編代碼:

bedf406e-2b08-11ec-82a8-dac502259ad0.png

像這樣,我們得到了正確的動作。

中斷服務程序

在中斷服務程序中,經常會修改一些全局變量值,來作為主程序中的判斷條件。例如,在串口中斷服務程序中,可能會檢測是否接收到了ETX(假如是消息的結束標識符)字符。如果接收到了ETX,ISR設置一個全局標志位。

錯誤的做法:

bf0fa740-2b08-11ec-82a8-dac502259ad0.png

在關閉編譯器優化的情況下,程序可能執行正常。然而,任何像樣點而優化都會“break”這段程序。問題是編譯器并不知道etx_rcvd可能被ISR中被修改。編譯器只知道,表達式!ext_rcvd始終為真,你講用于無法退出循環。結果,循環后面的代碼可能被編譯器優化掉。

幸運的話,你的編譯器可能會發出警告;不幸的話,(或者你不認真的查看編譯器警告),你的程序無法正常執行。當然,你可以責怪編譯器執行了“糟糕的優化”。

解決方式是,將變量etx_rcvd聲明為volatile,所有問題(當然,也可能是部分問題)就消失了。

多線程應用

在實時系統中,盡管有想queues,pipes等這些同步機制,使用全局變量實現兩個任務共享信息的做法依然很常見。即使在你的程序中加入了搶占式調度器,你的編譯器依然無法知道什么是上下文切換,或何時發生上下文切換。因此從概念上講,多任務修改全局變量的的做法與中斷服務程序中修改全局變量的做法是相同的。

因此,所有這類全局變量都應該聲明為volatile。

例如下面的程序:

bf0fa740-2b08-11ec-82a8-dac502259ad0.png

當打開編譯器優化時,這段程序可能執行失敗。解決方法是將cntr聲明為volatile。

總結

一些編譯器允許你把所有的變量隱式的聲明為volatile。請抵制這種誘惑,因為它會令你不再思考,當然也會導致生成低效的代碼。

另外,也不要責怪優化器或直接把它關掉。現代的優化器已經足夠優秀,我已經記不清上次遇到優化bug是什么時候了。相反,我常常看到程序員們錯誤的使用volatile。

如果你被要求去修改一個很古怪的代碼,請在程序中查找一下volatile關鍵字;如果你什么也沒有找到,上面討論的例子可以向你提供一些解決問題的思路。
編輯:jq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 串口
    +關注

    關注

    14

    文章

    1554

    瀏覽量

    76523
  • 程序
    +關注

    關注

    117

    文章

    3787

    瀏覽量

    81049
  • 代碼
    +關注

    關注

    30

    文章

    4788

    瀏覽量

    68616
  • 編譯器
    +關注

    關注

    1

    文章

    1634

    瀏覽量

    49133
  • volatile
    +關注

    關注

    0

    文章

    45

    瀏覽量

    13031

原文標題:教科書沒有講的C語言volatile用法

文章出處:【微信號:c-stm32,微信公眾號:STM32嵌入式開發】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    MSP430f5529一直都沒有輸出是怎么回事?

    用普通io控制的cs,sclk,din,芯片用的是MSP430f5529,一直都沒有輸出,求助
    發表于 12-24 07:00

    配置DAC63002輸出電流(uA),無論配置多大,都沒有輸出,為什么?

    配置DAC63002輸出電流(uA),無論配置多大,都沒有輸出。VDD 5V,1.8V I2C,2路電流模式,正值輸出。
    發表于 11-18 07:08

    MSC1202Y3使用各種ISP軟件(STC_ISP, IAR)進行燒錄,都沒有響應,為什么?

    我嘗試使用各種ISP軟件(STC_ISP, IAR)進行燒錄,都沒有響應。在網上查詢一些資料后發現有TI Downloader程序,但這個是針對EVM版使用的,EVM版已經停產,并且這個程序只能在Windows XP打開。有什么辦法解決燒錄問題嗎?
    發表于 11-15 07:25

    設計ADS7952時,發現采用手動模式和自動2模式都沒有數據輸出,為什么?

    我們在設計ADS7952時,發現采用手動模式和自動2模式都沒有數據輸出。 原理圖如下: 目前在ch0測得有電壓, 手動模式發送12次(0X1840)讀取0通道(12次),數據為0;用萬用表測量
    發表于 11-13 07:33

    PurePath Studio組件窗口中,與回聲消除的相關組件都沒有找到是怎么回事?

    PurePath Studio組件窗口中,與回聲消除的相關組件都沒有找到,比如AEC_Decim,AEC_32,AEC_CNG, AEC_Interp等組件都找不到,是PurePath Studio版本太舊了嗎,如何獲取新版本或者更新組件?謝謝
    發表于 11-04 08:31

    用freescale的CPU做host連接tlv320aic3254,在播放音樂時,i2sWclk,Bclk都沒有信號怎么解決?

    目前我們的項目是:用freescale的 CPU做host連接tlv320aic3254,是通過i2s連接傳輸信號的;the sampling rate 設置是44.1KHz,Mclk是24M; 目前問題是:在播放音樂時,i2sWclk,Bclk都沒有信號;
    發表于 10-22 07:40

    TAS5558不管輸入音頻怎么變換,輸出都沒有改變,為什么?

    0x4C.但是輸出的PWM波一直都是203.5KHz,不管輸入音頻怎么變換,輸出都沒有改變,看了很多天文檔,試著配置了很多寄存器,都沒有效果.實在是不知道應該怎么配置了,我需要用到的功能就是能有調制輸出就行了其它的功能都不需要,
    發表于 10-21 06:36

    用TPA2005D1做SIM800C的音頻輸出功放,然后接喇叭一點聲音都沒有,為什么?

    你好,我選用TPA2005D1做SIM800C的音頻輸出功放,然后接喇叭,一點聲音都沒有 如果SIM800C直接接喇叭,是有聲音的,聲音很小,電路圖如下,請大神幫忙看看
    發表于 10-18 06:38

    es8323使用tinyplay tinycap播放/錄音都沒有聲音,為什么?

    Android 音頻 es8323 codec芯片,使用tinyplay tinycap 播放/錄音都沒有聲音。
    發表于 09-30 08:27

    NA321的figure9一直都沒有實現放大是為什么?

    NA321的figure9有人用過嗎真的可以實現嗎為什么我一直都沒有實現放大?
    發表于 09-12 06:59

    lmh6518配置為LG模式時,無論增益配置為多少,都沒有信號輸出,為什么?

    500mv的信號,增益設置為38.8db,信號出來只有180mv,經過兩次阻抗匹配理論增益應該還有32.8dB。請問是技術手冊理解錯了還是可能的其他什么問題?對輔助輸出及濾波器帶寬的控制都沒有
    發表于 09-05 07:37

    使用pspice軟件進行仿真,始終都沒有高低電平信號出現,為什么?

    使用pspice軟件進行仿真,如圖出現問題,始終都沒有高低電平信號出現。
    發表于 08-20 06:05

    ESP32C3燒錄fast_scan的例程代碼,怎么一點東西都沒有顯示的?

    最近研究ESP32C3的WIFI 部分,燒錄fast_scan的例程代碼,怎么一點東西都沒有顯示的?只是顯示了ESP32的MAC地址?什么東西都沒有顯示或者動作了?我是不是要在menuconfig設置某些東西才能掃描AP?還是要
    發表于 06-17 06:08

    請問stm32復位電路為什么都沒有放電二極管?

    好多資料里面,stm32復位電路為什么都沒有放電二極管?
    發表于 04-01 08:18

    E203不顯示pass與fail是怎么回事,.log里什么都沒有還沒報錯?

    蜂鳥E203自測試用例失敗,不顯示pass與fail怎么回事,.log里什么都沒有,還沒報錯
    發表于 01-10 07:56
    主站蜘蛛池模板: 三级第一页| 国产美女精品视频免费观看| 国产色妞妞在线观看| 久插| 91视频精品| 黄色毛片儿| 丁香亚洲综合五月天婷婷| 一级一级毛片免费播放| 久操福利视频| 国产成人综合亚洲怡春院| 亚洲淫视频| 成人午夜性视频欧美成人| 在线观看播放视频www| 四虎日韩| 亚洲影视自拍揄拍愉拍| 一区在线播放| 欧美freesex10一|3| 天天爱夜夜| 5g影院天天| 日日艹| 天天射天天干天天操| 欧美视频三区| 狠狠狠狠狠操| 欧美激情第一欧美在线| 色多多视频在线观看| 天天操天天艹| 一级视频在线观看| 爱爱的免费视频| 天天躁狠狠躁夜躁2021| 老汉影视永久免费视频| 国产伦精品一区二区三区网站| 婷婷深爱五月| 天天操天天操天天操香蕉| 在线免费观看一级毛片| bt 电影天堂| 欧美午夜寂寞影院安卓列表| 久久免费特黄毛片| 欧美18性欧美黑吊| 久碰香蕉精品视频在线观看| 插插插天天| 欧美在线精品一区二区三区|