亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

蟲蟲首頁| 資源下載| 資源專輯| 精品軟件
登錄| 注冊

您現(xiàn)在的位置是:首頁 > 技術(shù)閱讀 >  如何使用C的volatile關(guān)鍵字

如何使用C的volatile關(guān)鍵字

時間:2024-05-31

首先聲明本文譯自國外網(wǎng)站的一篇文章,原文鏈接如下:

https://barrgroup.com/embedded-systems/how-to/c-volatile-keyword

建議有條件的直接閱讀英文原版??赡茏x了這篇文章后,你會有所懷疑,因為你平時可能遇到過下面出現(xiàn)的情況,但是你并沒有添加volatile關(guān)鍵字,程序任然正常的運行,個人覺得可能有以下的原因:

1.其實BUG出現(xiàn)了,但是難以復(fù)現(xiàn),所以被你忽略了

2.現(xiàn)在的優(yōu)化器足夠智能,即使打開了優(yōu)化,也能避免這些BUG的出現(xiàn)

正文開始

許多程序員對C的volatile關(guān)鍵字了解得很少。這并不奇怪,因為大多數(shù)C文章對它都是一兩句話避而不談。這篇文章將教你正確的使用它。

在你的C/C++嵌入式代碼中你是否經(jīng)歷過以下情況?

代碼正常運行--直到你使能了編譯器優(yōu)化

代碼正常運行--直到你使能了中斷

奇怪的硬件驅(qū)動程序

RTOS任務(wù)工作正常--直到你添加了其它任務(wù)

如果你對上面任意一個的回答為"是",那么意味著你沒有使用volatile關(guān)鍵字。許多程序員和你一樣對volatile關(guān)鍵字了解得很少。遺憾的是,大多數(shù)關(guān)于C編程語言的書只用一兩句話就避開它。

【正確的使用volatile是消除BUG的一部分  Embedded C Coding Standard】

C關(guān)鍵字volatile是一個限定符,在變量聲明的時候應(yīng)用它。它告訴編譯器這個變量的值可能隨時被改變--編譯器不要去優(yōu)化它。影響是非常嚴重的。但是,在剖析它之前,我們先看一下它的語法。

C關(guān)鍵字volatile的語法

聲明一個變量為volatile,就在這個變量聲明的數(shù)據(jù)類型前面或者后面加一個volatile關(guān)鍵字。下面兩個實例都聲明一個無符號16位整型變量為volatile整型:


volatile uint16_t x; 
uint16_t volatile y;


現(xiàn)在,實際證明指向volatile變量的指針也是非常普遍的,特別是內(nèi)存映射I/O寄存器。下面兩個聲明都將p_reg聲明為一個volatile的無符號8位整型指針:


volatile uint8_t * p_reg; 
uint8_t volatile * p_reg;


指向非volatile數(shù)據(jù)的volatile指針是非常少見的,但是我最好還是講一下語法:


uint16_t * volatile p_x;


并且,為了完整性,如果你真的需要一個指向volatile數(shù)據(jù)的volatile指針,你可以這樣寫:


uint16_t volatile * volatile p_y;


順便提一句,如果你想得到一個更好的解釋對于如何選擇在哪兒放置volatile以及為什么要放在數(shù)據(jù)類型的后面(例如,int volatile * foo),可以閱讀Dan Sak's的欄目,"Top-Level cv-Qualifiers in Function Parameters" (Embedded Systems Programming, February 2000, p. 63)。

最后,如果你將volatile應(yīng)用于結(jié)構(gòu)體或者共用體,那么整個結(jié)構(gòu)體或者共用體就都是volatile的。如果你并不是想這樣,你可以對結(jié)構(gòu)體或者共用體中需要的成員單獨的添加volatile限定符。

正確的使用C的volatile關(guān)鍵字

如果一個變量的值會被意想不到的修改那它應(yīng)該被volatile修飾,實際上,只有三種類型的變量可以被修改:

1.內(nèi)存映射外設(shè)寄存器

2.被中斷服務(wù)程序修改的全局變量

3.多線程內(nèi)部的多任務(wù)訪問的全局變量

我們將在下面的章節(jié)討論每一種情況。

外設(shè)寄存器

嵌入式系統(tǒng)包含真正的硬件,通常帶有復(fù)雜的外設(shè)。這些外設(shè)包含可能被程序流異步更改的寄存器。在一個非常簡單的程序中,包含一個8位的狀態(tài)寄存器,它的內(nèi)存地址被映射到0x1234。需要你輪詢這個狀態(tài)寄存器直到它的值變?yōu)榉?。不正確的實現(xiàn)如下:


uint8_t * p_reg = (uint8_t *) 0x1234;

// Wait for register to read non-zero 
do { ... } while (0 == *p_reg)


一旦你打開編譯器優(yōu)化,這段代碼幾乎肯定會失敗。這是因為編譯器將生成如下的匯編語言(這里以16位x86機器為例):


mov p_reg, #0x1234
  mov a, @p_reg
loop:
  ...
  bz loop


優(yōu)化器的理由很簡單:它已經(jīng)把變量的值讀取到了累加器中(對應(yīng)匯編代碼第二行),后面就不需要再重復(fù)讀取了,這樣的話這個值總是相同的。因此,從匯編代碼的第三行開始就進入了一個死循環(huán)。要強制編譯器如我們想的那樣做,我們需要修改聲明如下:


uint8_t volatile * p_reg = (uint8_t volatile *) 0x1234;


匯編代碼現(xiàn)在看起來就像這樣:


mov p_reg, #0x1234
loop:
  ...
  mov a, @p_reg
  bz loop


因此實現(xiàn)了我們想要的行為。

當(dāng)具有特殊屬性的寄存器操作沒有volatile聲明時就會產(chǎn)生一些微妙的BUG。例如,許多外設(shè)具有通過簡單的讀取就能清除它們的寄存器。在這種情況下,額外的讀取可能會導(dǎo)致超出預(yù)期的行為。

中斷服務(wù)程序

中斷服務(wù)程序通常設(shè)置在主線代碼中被測試的變量。例如一個串口中斷程序也許測試每個收到的字符是否是一個ETX字符(用以表示消息的結(jié)尾),如果這個字符是ETX,中斷服務(wù)程序也許設(shè)置一個全局標志。一個不正確的實現(xiàn)可能如下:


bool gb_etx_found = false;

void main() 
{
    ... 
    while (!gb_etx_found) 
    {
        // Wait
    } 
    ...
}

interrupt void rx_isr(void) 
{
    ... 
    if (ETX == rx_char) 
    {
        gb_etx_found = true;
    } 
    ...
}


【注意:我們不提倡使用全局變量;這段代碼使用僅為了讓例程簡短/清晰。】

在編譯器優(yōu)化關(guān)閉的情況下,這段程序也許正常的工作。然而,任何一半像樣的優(yōu)化器都會"破壞"這段程序。問題是編譯器不知道這個變量gb_etx_found可以在中斷服務(wù)程序中被更改,這似乎從來沒有被調(diào)用過。

就編譯器而言,表達式!gb_ext_found在循環(huán)中每次都是一樣的結(jié)果,因此,你不要想那能夠退出循環(huán)。因而,所有在while循環(huán)之后的代碼都可能被優(yōu)化器簡單的移除。如果你夠幸運,編譯器將警告你。如果你不夠幸運(或者你還沒有學(xué)會認真對待編譯器警告),你的代碼將不幸地失敗。自然,這責(zé)任將歸咎于"糟糕的優(yōu)化器"。

解決方案是使用volatile聲明變量gb_etx_found。這樣,程序就會按照你的預(yù)期正常工作。

多線程應(yīng)用

在實時操作系統(tǒng)中盡管存在隊列,管道,及其它調(diào)度感知的通信機制,但RTOS任務(wù)任然可能通過一段共享內(nèi)存來交換信息。當(dāng)你添加一個搶占式調(diào)度器到你的代碼中時,你的編譯器并不知道什么是上下文切換或者它何時發(fā)生,因此,一個任務(wù)異步修改一個共享的全局內(nèi)容就和中斷服務(wù)程序討論的情況差不多。因此所有全局對象(變量,內(nèi)存緩沖區(qū),硬件寄存器等等)都必須聲明為volatile以防止編譯器優(yōu)化而引入的不可預(yù)料的行為。例如,下面的代碼詢問問題:


uint8_t gn_bluetask_runs = 0;

void red_task (void) 
{   
    while (4 < gn_bluetask_runs) 
    {
        ...
    } 
    // Exit after 4 iterations of blue_task.
}

void blue_task (void) 
{
    for (;;)
    {
        ...
        gn_bluetask_runs++;
        ...
    }
}


這段代碼將失敗一旦編譯器優(yōu)化被使能。使用volatile聲明gn_bluetask_runs是解決這個問題的正確方式。

【注意:我們不提倡使用全局變量,這段代碼使用全局變量僅僅是因為它正在說明volatile和全局變量的關(guān)系?!?/p>

【警告:被任務(wù)及中斷共享的全局變量還應(yīng)該被保護以防止競爭,比如通過互斥量?!?/p>

最后的想法

一些編譯器允許你隱式的聲明所有變量為volatile,抵制這種誘惑,因為它本質(zhì)上是思想的替代品。這也潛在的導(dǎo)致代碼效率降低。

另外,當(dāng)你的程序出現(xiàn)非預(yù)期的行為時,不要責(zé)備優(yōu)化器或者關(guān)掉它?,F(xiàn)代C/C++優(yōu)化器是如此出色,以至于我不記得上次遇到了優(yōu)化BUG。相反,我經(jīng)常遇到程序員使用volatile失敗。如果給你一份行為怪異的代碼去"修復(fù)",請對volatile執(zhí)行g(shù)rep。如果grep為空,這里給出的示例可能是開始查找問題的好地方。



下面是我的公眾號二維碼,歡迎關(guān)注。


亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
美女精品在线| 久久久久久久久久久久久9999| 国产精品黄视频| 国产精品亚洲成人| 国产精品综合不卡av| 国产精品美女主播| 在线观看亚洲a| 中文日韩电影网站| 久久久久成人精品| 欧美日本韩国一区二区三区| 国产精品欧美在线| 在线看片欧美| 亚洲欧美日产图| 麻豆国产精品777777在线| 欧美日韩视频第一区| 国内精品视频666| 99精品99| 欧美成人精品一区二区三区| 国产精品成人免费| 国产伊人精品| 一卡二卡3卡四卡高清精品视频| 亚洲综合国产| 欧美精品国产精品| 好看不卡的中文字幕| 一区二区欧美亚洲| 久久国产乱子精品免费女| 欧美成人免费va影院高清| 国产一区二区久久精品| 夜夜嗨一区二区| 欧美精品一区二区三区久久久竹菊| 国产日韩一区在线| 欧美一区二区啪啪| 国产精品一区二区a| 亚洲午夜小视频| 欧美性猛交xxxx乱大交蜜桃| 91久久久国产精品| 欧美xxx在线观看| 亚洲高清在线观看| 久久一区二区三区超碰国产精品| 国产日韩欧美在线视频观看| 在线视频亚洲| 欧美午夜女人视频在线| 99av国产精品欲麻豆| 欧美国产在线电影| 亚洲欧洲一二三| 欧美日本亚洲| 亚洲视频电影图片偷拍一区| 欧美日韩网站| 亚洲自拍电影| 国产伦精品一区二区三区视频孕妇 | 久久久在线视频| 国产精品一区二区三区乱码| 亚洲欧美美女| 一区二区三区在线观看视频| 久久综合狠狠综合久久激情| 亚洲国产导航| 欧美天天影院| 久久精品国产亚洲5555| 极品少妇一区二区三区精品视频| 亚洲综合激情| 1024日韩| 国产精品久久久久久久久久免费看 | 一区二区三区日韩| 欧美激情一区在线| 亚洲一区二区3| 国产午夜久久| 亚洲国产欧美国产综合一区| 欧美久久九九| 欧美一区二区三区日韩| 在线观看一区二区精品视频| 欧美日韩精品免费观看视频完整 | 六月婷婷一区| 欧美视频日韩视频| 久久精品亚洲精品| aⅴ色国产欧美| 狠狠88综合久久久久综合网| 欧美精品亚洲二区| 欧美在线三区| 一区二区三区国产在线| 黄网站免费久久| 国产精品进线69影院| 免费不卡在线视频| 欧美一区二区黄| 一区二区三区 在线观看视| 国产在线日韩| 国产精品美女久久久免费| 你懂的成人av| 久久国产精品99国产精| 中文精品视频一区二区在线观看| 一区二区三区在线高清| 国产精品久久久久999| 欧美极品一区二区三区| 久久三级福利| 久久久久久穴| 香蕉av777xxx色综合一区| 亚洲乱码久久| 亚洲久色影视| 亚洲福利专区| 亚洲福利在线看| 国产在线一区二区三区四区| 欧美剧在线免费观看网站| 免费不卡亚洲欧美| 久久亚洲精选| 久久中文字幕导航| 久久久久成人精品免费播放动漫| 午夜精品一区二区三区电影天堂| 亚洲图片欧洲图片av| 一本一道久久综合狠狠老精东影业| 欧美精品免费观看二区| 久久免费视频在线| 久久一区精品| 欧美高清视频一区二区三区在线观看| 欧美在线影院| 久久躁日日躁aaaaxxxx| 蜜臀av性久久久久蜜臀aⅴ四虎| 久久久亚洲国产美女国产盗摄| 久久偷看各类wc女厕嘘嘘偷窃| 久久久久久免费| 欧美国产欧美亚州国产日韩mv天天看完整| 噜噜噜噜噜久久久久久91| 欧美.www| 欧美三级精品| 国产一区99| 亚洲国产高潮在线观看| 亚洲精品自在久久| 亚洲天堂网在线观看| 午夜精品久久久久| 久久久国产亚洲精品| 欧美大片网址| 国产精品vvv| 国产午夜精品久久久久久免费视| 国产亚洲精品aa| 久久精品国产99精品国产亚洲性色 | 国产精品中文字幕欧美| 欧美日韩亚洲综合在线| 欧美伦理a级免费电影| 欧美一级片在线播放| 新67194成人永久网站| 亚洲主播在线观看| 欧美亚洲日本国产| 欧美成人免费小视频| 99精品热视频| 国产私拍一区| 国产精品乱码久久久久久| 亚洲精品久久视频| 亚洲第一网站免费视频| 一区精品在线播放| 国产模特精品视频久久久久| 欧美三级午夜理伦三级中视频| 国产精品网曝门| 亚洲一区在线视频| 美女网站久久| 一区二区精品在线| 在线精品国精品国产尤物884a| 国产综合视频| 久久久久一区二区| 一区二区日韩精品| 国语自产精品视频在线看8查询8 | 欧美日韩美女在线| 欧美激情影院| 欧美大学生性色视频| 亚洲一区二区三区涩| 狠狠综合久久av一区二区小说| 欧美日韩国产综合视频在线| 欧美大片免费观看| 欧美激情欧美狂野欧美精品| 欧美一区激情视频在线观看| 9i看片成人免费高清| 亚洲国产天堂久久综合网| 亚洲精品视频啊美女在线直播| 亚洲国产精品成人一区二区| 韩国成人福利片在线播放| 国产精品裸体一区二区三区| 久久久久一区二区三区| 欧美日韩国产精品一区| 国产精品视频九色porn| 国产精品入口麻豆原神| 国产精品家庭影院| 国产精品国产三级国产普通话99 | 国内精品伊人久久久久av影院 | 久久亚洲精品视频| 久久色中文字幕| 久久久91精品| 国产揄拍国内精品对白| 亚洲国产精品久久91精品| 亚洲国产99| 99精品视频免费观看视频| 欧美在线播放视频| 国产精品久久久久久影视| 亚洲第一狼人社区| 9国产精品视频| 久久精品国产亚洲一区二区三区| 欧美精选午夜久久久乱码6080| 国产在线播放一区二区三区| 夜夜嗨av一区二区三区| 国产精品99久久久久久久久久久久| 欧美日韩一区二区免费在线观看| 精品51国产黑色丝袜高跟鞋| 久久精品在线视频| 国产丝袜美腿一区二区三区|