91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

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

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

3天內(nèi)不再提示

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

工程師 ? 來源:嵌入式大雜燴 ? 作者:嵌入式大雜燴 ? 2020-09-15 13:49 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

來源:嵌入式大雜燴

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

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

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

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

全局變量在多線程或多任務(wù)間共享

全局變量在常規(guī)代碼和中斷服務(wù)程序間共享

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

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

舉個栗子,還是以之前文章的傳感器為例,實際應用中傳感器可能是下面這樣的數(shù)據(jù)結(jié)構(gòu)來描述:

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

假定這個傳感器數(shù)據(jù)結(jié)構(gòu)有這樣一些被訪問的可能:

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

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

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

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

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

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

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

0x43964000 /* 浮點數(shù)300.5的16進制*/0x43488000 /* 浮點數(shù)200.5的16進制*/

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

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

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

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

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

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

初學者甚至不會用struct將相關(guān)的數(shù)據(jù)包在一起,其結(jié)果是代碼里到處都是基本類型的全局變量。一些簡單的業(yè)務(wù)邏輯實現(xiàn)變成一個復雜的代碼,數(shù)據(jù)信息流向一團亂麻。

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

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

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

那么uart協(xié)議解析要怎么做呢?

void interprete_uart(void){ if(rx_msg.flag) { rx_msg.flag = false; /*報文完整性檢查*/ 。。. /*設(shè)置溫度配置*/ 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){ /*負責底層操作,啟動中斷傳輸*/}/*提供應答數(shù)據(jù)接口*/void reply_temperature_setting(T_SENSOR sensor){ /*解析傳入?yún)?shù)并封裝應答報文*/}

如此一來,數(shù)據(jù)流向?qū)⒆兊煤芮逦?,串口接收到?shù)據(jù)更新范圍配置時,也無需開關(guān)中斷了,從應用角度幾乎見不到全局變量。當然這樣做的代價就是會增加一些棧開銷。但是這種代價還是值得的。

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

int set_upper_range(float range){ T_SENSOR temp = temperature; temp.upper_range = range; /*實現(xiàn)范圍合理性檢查*/ if(check_range(temp)) { /*兩個結(jié)構(gòu)體變量可以直接賦值*/ 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; }

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

多任務(wù)/多線程環(huán)境上面描述其實本質(zhì)上描述了裸機程序里,普通模式運行程序與中斷服務(wù)程序?qū)τ谂R界資源的競爭。事實上現(xiàn)在不管是單片機,還是處理器,大多都是基于一個操作系統(tǒng)進行應用開發(fā)。甚至還可能是多核芯片,這里就存在并發(fā)競爭訪問資源的問題。

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

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

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

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

    關(guān)注

    22

    文章

    2123

    瀏覽量

    77106
  • 全局變量
    +關(guān)注

    關(guān)注

    1

    文章

    28

    瀏覽量

    9272
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    嵌入式C語言中各變量存儲位置

    局部變量、局部靜態(tài)變量、全局變量全局靜態(tài)變量區(qū)別如下: 局部變量: 棧區(qū); 局部靜態(tài)
    發(fā)表于 12-25 07:54

    如何搞定嵌入式 C語言中的全局變量問題?

    大家好,今天分享一篇關(guān)于嵌入式C編程中全局變量問題的文章。希望對大家有所啟發(fā)。 嵌入式特別是單片機os-less的程序,最易范的錯誤是全局變量滿天飛。 這個現(xiàn)象在早期匯編轉(zhuǎn)型過來的程序員以及初學者
    發(fā)表于 12-16 06:54

    C語言全局變量重點使用

    全局變量絕不會位于寄存器中。使用指針或者函數(shù)調(diào)用,可以直接修改全局變量的值。 因此,編譯器不能將全局變量的值緩存在寄存器中,但這在使用全局變量時便需要額外的 (常常是不必要的)讀取和存
    發(fā)表于 12-12 06:58

    第7章 變量進階與點陣LED(7.1 7.2)

    知識——變量的作用域和存儲類別。 7.1變量的作用域 所謂的作用域就是指變量起作用的范圍,也是變量的有效范圍。變量按他的作用域可以分為局部
    的頭像 發(fā)表于 12-10 16:25 ?352次閱讀

    請問C語言開發(fā)單片機為什么大多數(shù)都采用全局變量的形式?

    C語言代碼,大多數(shù)都是使用全局變量,也就是用很多函數(shù)來操作這些變量,比如函數(shù)1把一個全局變量經(jīng)過一系列復雜的算法計算后改變了這個全局變量的值,然后函數(shù)2再拿著函數(shù)1處理過的這個
    發(fā)表于 12-04 07:47

    哪些場合會用到volatile關(guān)鍵字?

    當你理解 volatile關(guān)鍵字的含義之后,你就能明白,其實很多場合都能用到 volatile關(guān)鍵字。 1.全局變量單片機開發(fā),難免會用到全局變量。一些初級工程師,更是全局變量滿天飛。這種情況下
    發(fā)表于 11-25 08:19

    常用變量的介紹

    extern:用在全局變量上表示該變量在其他文件中已經(jīng)定義;用在函數(shù)上作用同全局變量; static:用在全局變量上,和非靜態(tài)全局變量相比,
    發(fā)表于 11-21 07:05

    C語言開發(fā)單片機為什么大多數(shù)都采用全局變量的形式?

    單片機的芯片資源從來都是 “精打細算” 的級別,CPU 主頻普遍不高,RAM 總?cè)萘勘揪途o張,分給??臻g的更是少得可憐。要是像普通軟件那樣,依賴函數(shù)返回值傳遞數(shù)據(jù)、頻繁用局部變量周轉(zhuǎn),一來二去占用
    的頭像 發(fā)表于 11-12 14:29 ?424次閱讀
    C語言開發(fā)單片機為什么大多數(shù)都采用<b class='flag-5'>全局變量</b>的形式?

    STM32H755雙核單片機的使用疑問求解?

    我再使用STM32H755單片機時候,想用M7內(nèi)核和M4內(nèi)核,分時操作串口,可以這樣使用嗎? 還有就是全局變量可以同時被兩個核操作嘛?
    發(fā)表于 11-11 07:16

    按照芯來文檔設(shè)置可以通過segger IDE debug了,但是沒法看全局或者局部變量值,怎么解決?

    如題,按照芯來文檔設(shè)置可以通過segger IDE debug了,但是沒法看全局或者局部變量值,很麻煩。有遇到過解決了的嗎?
    發(fā)表于 10-20 09:20

    請問Modus Toolbox下針對CYW20719B2編程,能否指定全局變量地址?

    請問Modus Toolbox 下針對CYW20719B2編程,能否指定全局變量地址?
    發(fā)表于 07-08 07:20

    Cubeide1.18.1在線調(diào)試改變\"現(xiàn)場表達式\"中的值提示找不到地址怎么解決?

    Cubeide1.18.1在線調(diào)試時,在\"現(xiàn)場表達式\"中添加全局變量,然后改變其數(shù)值,Console窗口提示: Failed to read all registers
    發(fā)表于 04-27 06:18

    static在單片機中的妙用

    了呢?一起來看下吧一、修飾變量第一個作用修飾變量,變量又分為局部變量全局變量,但它們都存在內(nèi)存的靜態(tài)區(qū)。 對于靜態(tài)區(qū),堆棧等等這些區(qū)域的概
    發(fā)表于 04-02 13:50 ?1次下載

    VirtualLab Fusion應用:參數(shù)耦合

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

    求助,關(guān)于STM32G070封裝HAL_GetTick的疑問求解

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