色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創作中心

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

3天內不再提示

分析如何遠離漫天飛舞的全局變量

工程師 ? 來源:嵌入式大雜燴 ? 作者:嵌入式大雜燴 ? 2020-09-15 13:49 ? 次閱讀

來源:嵌入式大雜燴

前篇 《由static來談談模塊封裝》 基本實現了對外隱藏屬性,隱藏局部模塊函數,開放接口的功能。對于這個話題還有些點沒有深入探討:為什么要這樣做?以及這樣做的好處。或許很多剛剛開始用C或者其他面向對象編程語言(比如C++)的小伙伴們,常常在一個項目里為了圖省事,整了很多全局對象、全局變量滿天飛,這樣做其實是有很多弊端,本文來聊聊這個話題。

先談談全局變量的特點全局變量(Global Variables):在計算機編程語言中,所謂全局變量是指具有全局作用域的變量,這意味著它在整個程序中是可見的,因此是可訪問的。所謂可訪問,是指全局可讀、全局可寫。在編譯語言中,全局變量通常是靜態變量,其范圍(生命周期)是程序的整個運行時。當然解釋性語言除外,解釋性語言包括命令行解釋器(比如pythonJava script,shell等)中,全局變量通常在聲明時由解釋器動態分配,這是由于解釋性語言是讀取》解釋》執行模式,不像編譯性語言,運行前可預知變量屬性,解釋性語言讀取解釋前無從獲取變量屬性。

在C/C++編程語言中,全局變量的這種全局可見性特點,濫用全局變量會讓代碼表現當相當邪惡!如果使用全局變量,就意味著下面這些場景的存在:

實際代碼可能有很多地方在讀、在寫全局變量

全局變量在多線程或多任務間共享

全局變量在常規代碼和中斷服務程序間共享

為啥說全局變量很邪惡?單片機裸機編程或許你會說,我就這樣用?咋了?軟件也跑的很好啊?來看看這個場景:

一個超字寬的變量(比如16位單片機,字寬即為16位),正被一個常規代碼在寫變量數據域時且還沒寫完,啪嘰,來了個中斷!中斷一來,CPU趕緊把手里的活兒停下來,奔過去處理中斷了,不巧在中斷函數里,該變量因業務需求有需要寫這個變量有經驗的不這么寫,僅為了方便說明:

舉個栗子,還是以之前文章的傳感器為例,實際應用中傳感器可能是下面這樣的數據結構來描述:

#ifndef _SENSOR_H_#define _SENSOR_H_typedef struct _t_sensor{ /* 測量值與測量范圍及單位有關 */ float value; /* 測量范圍,根據采樣值映射 */ float upper_range; float lower_range; /* 溫度單位 */ unsiged char unit;}T_SENSOR;/*假定是一個溫度測量產品*/extern T_SENSOR temperature;#endif _SENSOR_H_

假定這個傳感器數據結構有這樣一些被訪問的可能:

上位機會改寫測量數據的范圍及單位,串口通信中斷服務程序直接寫這個全局變量中的上下限數據域

LCD操作界面可改寫溫度上下限范圍。

測量更新模塊根據當前范圍及單位配置,將傳感器采集到的數據映射為測量值。

這些需求用例,用圖描述一下:

比如用戶操作HMI界面正改寫溫度范圍,而此時遠程上位機也正改寫溫度范圍,按上面這個做法,可能出現哪些邪惡的后果呢?

通過LCD界面寫入上限為300.5(假定原下限為0),此時遠程串口報文收到,程序直接在中斷服務程序將范圍修改為(-100,200.5),此時中斷返回,用戶可能接著修改下限為-200,則最終設備內的溫度范圍可能既不是(-100,200.5)也不是(-200,300.5),而可能是(-200,200.5)。這是一個易理解的數據混亂的場景。

現實中如果使用的單片機是8位/16位單片機,一條指令無法完成操作一個32位立即數,有可能才完成一個浮點數中某幾個字節,此時就被中斷打斷寫入200,然后中斷返回后繼續寫入剩下字節,數據可能會變得非常詭異!利用http://www.speedfly.cn/tools/hexconvert/ 在線工具轉換浮點數到16進制:

0x43964000 /* 浮點數300.5的16進制*/0x43488000 /* 浮點數200.5的16進制*/

假定中斷進入時,HMI界面程序寫入了0x4396前兩個字節,中斷返回時,上限改寫為200.5(0x43488000),此時繼續執行后面兩個字節寫入,則上限變成為(0x43484000),來看看這個數是多大?變成了200.25,這是不是很邪惡?

或許有的朋友會說,可以在LCD寫范圍時關中斷嘛。誠然,可以這么做:

void hmi_operate(){ /*關中斷*/ _disable_interrupt(); /*改寫溫度范圍*/ 。。.。 /*開中斷*/ _enable_interrupt();}

但是如果這個全局變量有很多地方在改寫,為了數據安全,勢必就到處開/關中斷,這樣做的壞處:

經常開關中斷,勢必影響中斷響應,會有概率丟失異步中斷處理(比如串口按字節接收中斷,可能就會漏收字節),程序不健壯,工作不穩定。

到處訪問改寫,不易調試,群魔亂舞,代碼也不易維護。想加點東西,改點東西可能隨處都是坑,一不小心就掉坑里去了!

初學者甚至不會用struct將相關的數據包在一起,其結果是代碼里到處都是基本類型的全局變量。一些簡單的業務邏輯實現變成一個復雜的代碼,數據信息流向一團亂麻。

裸機程序策略對于上面這樣一個應用場景,怎么解決這種混亂的現象呢。這里分享一下我的思路,這里將主要的串口以及測量模塊的設計思路用UML圖描述一下大體思路:

如此一來,外部就看不到全局變量了,只需要調用對應的set/get方法即可實現讀寫訪問,由于是裸機前后臺程序,數據流向就變的非常清晰了。main函數的主循環大致就可能是這樣:

void main(void){ /*模塊初始化*/ init_uart(); init_temperature(); 。。.。 while(1) { interprete_uart(); /*可能是周期性調用*/ if(timer_100ms) { timer_100ms = 0; update_temperature(); } 。。.。 } }

那么uart協議解析要怎么做呢?

void interprete_uart(void){ if(rx_msg.flag) { rx_msg.flag = false; /*報文完整性檢查*/ 。。. /*設置溫度配置*/ set_upper_range(xxx); set_lower_range(xxx); set_unit(xxx); } if(tx_msg.flag) { tx_msg.flag = false; start_send(); }}static start_send(T_UART_MSG *pMsg){ /*負責底層操作,啟動中斷傳輸*/}/*提供應答數據接口*/void reply_temperature_setting(T_SENSOR sensor){ /*解析傳入參數并封裝應答報文*/}

如此一來,數據流向將變得很清晰,串口接收到數據更新范圍配置時,也無需開關中斷了,從應用角度幾乎見不到全局變量。當然這樣做的代價就是會增加一些棧開銷。但是這種代價還是值得的。

對于測量模塊的set函數思路稍做說明:

int set_upper_range(float range){ T_SENSOR temp = temperature; temp.upper_range = range; /*實現范圍合理性檢查*/ if(check_range(temp)) { /*兩個結構體變量可以直接賦值*/ temperature = temp; return 0; } else { return -1; }}int set_unit(E_UNIT unit){ if(unit》E_UNIT_F) return -1; adjust_range(&temperature,unit); temperature.unit = unit; }

上述代碼旨在分享個人的一些思路,其中或有不夠嚴謹的地方,但通過這樣的設計思路,應能大幅度遠離滿天飛的全局變量。

多任務/多線程環境上面描述其實本質上描述了裸機程序里,普通模式運行程序與中斷服務程序對于臨界資源的競爭。事實上現在不管是單片機,還是處理器,大多都是基于一個操作系統進行應用開發。甚至還可能是多核芯片,這里就存在并發競爭訪問資源的問題。

臨界資源:各任務/線程采取互斥的方式,實現共享的資源稱作臨界資源。屬于臨界資源的硬件串口打印、顯示等,軟件有消息緩沖隊列、變量、數組、緩沖區等。多任務/線程間應采取互斥方式,從而實現對這種資源的共享。

多任務/多線程情況下在寫模塊時,只需要封裝進保護機制即可。常見的保護機制有關中斷、信號量、互斥鎖等。在Linux內核中為應對多核并發訪問還有自旋鎖機制。由于篇幅所限,本文就不做展開了,先挖個坑,以后有機會再分享吧。

總結一下在前文介紹static文章的基礎上,相對更深入的介紹了為何需要隱藏屬性以及開放接口的做法。以及如何遠離邪惡的全局變量漫天飛舞的不良設計風格。

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

    關注

    22

    文章

    2116

    瀏覽量

    74612
  • 全局變量
    +關注

    關注

    1

    文章

    28

    瀏覽量

    9097
收藏 0人收藏

    評論

    相關推薦
    熱點推薦

    VirtualLab Fusion應用:參數耦合

    。 源代碼標簽包含以下三部分: 源代碼(中心區域) 全局變量/參數(右側上端) 選擇系統參數(右側底端) 6.參數耦合的一般示例 ?通常,利用代碼字典讀取所選參數并將其保存到變量(第4行)。 ?之后
    發表于 03-17 11:11

    求助,關于STM32G070封裝HAL_GetTick的疑問求解

    HAL_GetTick函數,默認使用了滴答定時器中斷,并使用了全局變量uwTick,這個變量是32位的,那變量溢出了就會從0開始,許多外設超時判斷的語句是HAL_GetTick() - Tickstart>TimeOut,
    發表于 03-14 07:20

    為什么同一個隊列引用的全局變量,運行在兩個子vi中發現隊列數據丟失了

    我創建了一個隊列,然后將隊列引用做了個全局變量,運行在兩個子vi中,一個是只入隊列,另一個是只出隊列。但我發現,一個字vi數據入隊列成功,檢查隊列元素數量也已經是1了,這時我運行另一個子vi,出隊列前檢查隊列數量發現為0了。隊列里的數據沒了。而且這個情況不是一直有,是偶爾發生。
    發表于 11-14 11:47

    labview主程序運行時如何引起子VI里的事件結構響應

    設計了一個程序需要通過主VI的按鍵控制子VI事件發生,設置了個全局變量作為媒介,但是值會變事件并不會發生
    發表于 11-10 13:04

    使用EMEM內存的幾個疑問求解?

    連接到 XBAR1),數據寫入和讀取將比其他存儲器花費更多時間。 那么,是否建議存儲普通全局變量/全局靜態變量? 3.EMEM 在多核應用中的優缺點?
    發表于 07-04 07:02

    通過設置全局變量I2S0,I2S1觸發DMA機制的疑問求解答

    在跟蹤esp32-web-camera的代碼時,看到了通過設置全局變量I2S0,I2S1,觸發DMA的機制,對于結構體i2s_dev_t的各字段不是很理解,不懂哪里有這方面的文檔,另外通過設置變量
    發表于 06-13 07:42

    LABVIEW調用DLL,DLL中包含全局變量不識別的問題

    頭文件中寫法如上,.cpp文件中寫法如下 導入DLL時,錯誤如下 這個報錯就很沒有道理 我在同樣的文件中按同樣的寫法,寫一個add(a,b,c)函數,同樣寫全局變量的話,它就不會報這樣的錯,所以我可以排除是頭文件或者預處理定義的問題。 很頭疼,有沒有大神指導一下。
    發表于 05-31 09:37

    TC375如何將變量值保存到非易失性存儲器中?

    我有一臺 TC375,正在開發工作室進行編程。 我的軟件有一個控制系統,它使用一組我可以調整的參數。 這些參數設置為全局變量。 一旦我對它們進行了調整,控制器復位后就無法保持它們的值。 是否有辦法使用閃存編程示例,用新值更新 Pflash 或 Dflash 中的地址,使其存儲在非易失性存儲器中?
    發表于 05-31 06:40

    keil中Logic Analyzer可以在硬件上在線調試,為什么把全局變量加入Logic Analyzer不顯示波形呢?

    keil中Logic Analyzer可以在硬件上在線調試,按照說明文檔上調試,用的是SW模式,為什么把全局變量加入Logic Analyzer不顯示波形呢?是不是時鐘頻率選擇的不合適?還是必須得對調試寄存器配置?
    發表于 05-16 06:47

    建立更多的全局變量的時候,如何使得PROGRAM SIZE不增大呢?

    今天發現,建立更多的全局變量的時候,PROGRAM SIZE同時也增大了,如何使得PROGRAM SIZE不增大呢?我對全局變量的初始化無要求。
    發表于 05-15 06:30

    COSMIC在外部中斷中修改全局變量后,發現在主程序中,修改的值又變回來了,為什么?

    我用的COSMIC,在外部中斷中修改全局變量后,發現在主程序中,修改的值又變回來了(比如說我想計數外部中斷的次數)。這是怎么回事?而我在定時中斷中卻可以修改全局變量
    發表于 05-13 08:45

    IAR調試STM32F4XX時,一下斷點就出現全局變量被覆蓋的情況是什么原因導致的?

    IAR調試STM32F405VG時,一下斷點就出現全局變量被覆蓋的情況。 //進入該函數后,單步的時候_X這個全局變量的內容被覆蓋,設置的func_triggered函數地址被改變,觸發
    發表于 05-11 06:52

    stm32 tim1輸入捕獲+DMA,如果長時間無脈寬信號,輸出報警信號怎么解決?

    要求:實現測量外部脈沖寬度,讀取脈寬后,清除脈寬數據,如果長時間無脈寬信號,輸出報警信號。 實現方式:使用stm32 tim1輸入捕獲+DMA方式,把捕獲的脈寬通過DMA方式存儲到全局變量中,軟件
    發表于 05-11 06:08

    使用IAR定義全局變量出現兩個同名不同地址變量是什么原因導致的?

    使用IAR定義全局變量出現兩個同名不同地址變量 systickCount和systickFlag都在另一個c文件里定義的,假設a.c,然后在a.h里聲明為外部變量,main.c
    發表于 05-10 06:09

    請問ucos中全局變量OSTime最終能累加到多少呢?

    在ucos-ii 中全局變量 OSTime 總是++請問最終能累加到多少呢? 若加到65530后 會自動歸零嗎?
    發表于 05-09 06:22
    主站蜘蛛池模板: 无码毛片内射白浆视频 | 亚洲免费一 | 国产欧美日韩中文视频在线 | 69精品国产人妻蜜桃国产毛片 | 成人免费在线观看 | 欧美丝袜女同 | 国产一级做a爰片久久毛片男 | 香蕉久久夜色精品国产小说 | 亚洲爱视频 | 国产一级毛片在线 | 伊人久久中文大香线蕉综合 | 亚洲免费视频在线观看 | 日日夜夜天天操 | 久久操热在线视频精品 | 国语自产视频在线不卡 | 忘忧草日本在线社区WWW电影 | 国产性夜夜性夜夜爽91 | 东京热 百度影音 | WWW国产色情在线观看APP | 日韩精品久久久久久久电影 | 男人的天堂色偷偷 | 麻豆精品一卡2卡三卡4卡免费观看 | 婷婷精品国产亚洲AV在线观看 | 国语对白嫖老妇胖老太 | HEYZO精品无码一区二区三区 | 浴室里强摁做开腿呻吟的漫画 | 久久99热这里只有精品66 | 日本久久精品免视看国产成人 | 国内外成人免费在线视频 | 日韩精品一区VR观看 | 国产亚洲日韩在线播放不卡 | 91黄色影院 | 国产白丝精品爽爽久久久久久蜜臀 | 野花日本免费完整版高清版动漫 | 日本久久久WWW成人免费毛片丨 | 我们中文在线观看免费完整版 | 国语对白刺激真实精品 | 欧美多人群p刺激交换电影 欧美多毛的大隂道 | 苍老师刺激的120分钟 | 被六个男人躁到一夜同性 | 国产精品路线1路线2路线 |

    電子發燒友

    中國電子工程師最喜歡的網站

    • 2931785位工程師會員交流學習
    • 獲取您個性化的科技前沿技術信息
    • 參加活動獲取豐厚的禮品