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

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

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

如何判定全局變量和局部變量

strongerHuang ? 來(lái)源:strongerHuang ? 作者:strongerHuang ? 2022-09-07 09:08 ? 次閱讀

何為變量?

變量一般可以細(xì)分為如下圖:

7f0d0b24-2e45-11ed-ba43-dac502259ad0.png

本節(jié)重點(diǎn)為了讓大家理解內(nèi)存模型的“棧”,暫時(shí)不考慮“靜態(tài)變量” 的情況,并約定如下:

“全局變量”僅僅默認(rèn)為“普通全局變量”;

“局部變量”僅僅默認(rèn)為“普通局部變量”。

如何判定全局變量和局部變量?

簡(jiǎn)單直觀的來(lái)說(shuō),全局變量就是在函數(shù)外面定義的變量,局部變量就是在函數(shù)內(nèi)部定義的變量,下面的例子能很清晰地說(shuō)明全局變量和局部變量的判定方法:

unsigned char a;//在函數(shù)外面定義的,所以是全局變量。
voidmain()//主函數(shù)
{
 unsigned char b;//在函數(shù)內(nèi)部定義的,所以是局部變量。
b=a;
while(1)
{

}
}

全局變量和局部變量的內(nèi)存模型

單片機(jī)內(nèi)存包括ROMRAM 兩部分,ROM存儲(chǔ)的是單片機(jī)程序中的指令和一些不可更改的常量數(shù)據(jù),而 RAM存放的是可以被更改的變量數(shù)據(jù);

也就是說(shuō),全局變量和局部變量都是存放在RAM,但是,雖然都是存放在 RAM,全局變量和局部變量之間的內(nèi)存模型還是有明顯的區(qū)別的。

因此,分了兩個(gè)不同的RAM區(qū),全局變量占用的 RAM區(qū)稱為全局?jǐn)?shù)據(jù)區(qū), 局部變量占用的 RAM 區(qū)稱為。

它們的內(nèi)存模型到底有什么本質(zhì)的區(qū)別呢?

全局?jǐn)?shù)據(jù)區(qū)就像你自己家的房間,是唯一的,一個(gè)房間的地址只能你一個(gè)人?。僭O(shè)你還是單身狗的時(shí)候),而且是永久的(sorry),所以說(shuō)每個(gè)全局變量都有唯一對(duì)應(yīng)的 RAM 地址, 不可能重復(fù)的。

就像客棧, 一年下來(lái)每天晚上住的人不一樣,每個(gè)人在里面居住的時(shí)間是有期限的,不是長(zhǎng)久的,一個(gè)房間的地址一年下來(lái)每天可能住進(jìn)不同的人,不是唯一的。

全局?jǐn)?shù)據(jù)區(qū)的全局變量擁有永久產(chǎn)權(quán),區(qū)的局部變量只能臨時(shí)居住在賓館客棧, 地址不是唯一的, 有期限的。

是給程序里所有函數(shù)內(nèi)部的局部變量共用的,函數(shù)被調(diào)用的時(shí)候,該函數(shù)內(nèi)部的每個(gè)局部變量就會(huì)被分配對(duì)應(yīng)到的某個(gè)RAM 地址,函數(shù)調(diào)用結(jié)束后,該局部變量就失效。

因此它對(duì)應(yīng)的 的RAM空間就被收回,以便給下一個(gè)被調(diào)用的函數(shù)的局部變量占用。

舉例借用“賓館客棧”來(lái)比喻局部變量所在的“?!薄?/p>

voidfunction(void);//子函數(shù)的聲明

voidfunction(void)//子函數(shù)的定義
{
unsignedchara;//局部變量
a=1;
}

voidmain()//主函數(shù)
{
function();//子函數(shù)的調(diào)用
}

我們看到單片機(jī)從主函數(shù) main 往下執(zhí)行, 首先遇到function()子函數(shù)的調(diào)用, 所以就跳到function()函數(shù)的定義那里開始執(zhí)行, 此時(shí)的局部變量 a 開始被分配在 RAM的“棧區(qū)” 的某個(gè)地址, 相當(dāng)于你入住賓館被分配到某個(gè)房間。

單片機(jī)執(zhí)行完子函數(shù)function() 后,局部變量 a 在 RAM 的棧區(qū)所分配的地址被收回, 局部變量a 消失,被收回的RAM地址可能會(huì)被系統(tǒng)重新分配給其它被調(diào)用的函數(shù)的局部變量。

此時(shí)相當(dāng)于你離開賓館,從此你跟那個(gè)賓館的房間沒有啥關(guān)系, 你原來(lái)在賓館入住的那個(gè)房間會(huì)被賓館老板重新分配給其他的客人入住。

全局變量的作用域是永久性不受范圍限制的,而局部變量的作用域就是它所在函數(shù)的內(nèi)部范圍。全局變量的全局?jǐn)?shù)據(jù)區(qū)是永久的私人房子,局部變量的棧是臨時(shí)居住的客棧。

總結(jié)如下

每定義一個(gè)新的全局變量,就意味著多開銷一個(gè)新的RAM 內(nèi)存。而每定義一個(gè)局部變量,只要在函數(shù)內(nèi)部所定義的局部變量總數(shù)不超過(guò)單片機(jī)的棧區(qū),此時(shí)的局部變量不開銷新的 RAM內(nèi)存, 因?yàn)榫植孔兞渴桥R時(shí)借用棧的, 使用后就還給棧,棧是公共區(qū), 可以重復(fù)利用,可以服務(wù)若干個(gè)不同的函數(shù)內(nèi)部的局部變量。

單片機(jī)每次進(jìn)入執(zhí)行函數(shù)時(shí),局部變量都會(huì)被初始化改變,而全局變量則不會(huì)被初始化, 全局變量是一直保存之前最后一次更改的值。

有哪些常見疑問?

全局?jǐn)?shù)據(jù)區(qū)棧區(qū)是誰(shuí)在幕后分配的, 怎么分配的?

是C編譯器自動(dòng)分配的, 至于怎么分配,誰(shuí)分配多一點(diǎn),誰(shuí)分配少一點(diǎn),C 編譯器會(huì)有一個(gè)默認(rèn)的比例分配, 我們一般都不用管。

棧區(qū)是臨時(shí)借用的,子函數(shù)被調(diào)用的時(shí)候,它內(nèi)部的局部變量才會(huì)“臨時(shí)” 被分配到“?!?區(qū)的某個(gè)地址,那么問題來(lái)了,誰(shuí)在幕后主持“棧區(qū)” 這些分配的工作?

單片機(jī)已經(jīng)上電開始運(yùn)行程序的時(shí)候,編譯器已經(jīng)不起作用,“棧區(qū)” 分配給函數(shù)內(nèi)部局部變量的工作,確實(shí)是 C 編譯器做的,但這是在單片機(jī)上電前。

C 編譯器就把所有函數(shù)內(nèi)部的局部變量的分配工作就規(guī)劃好了,都指定了如果某個(gè)函數(shù)一旦被調(diào)用,該函數(shù)內(nèi)部的哪個(gè)局部變量應(yīng)該分到“棧區(qū)” 的哪個(gè)地址,C 編譯器都是事先把這些“后事” 都交代完畢了才結(jié)束自己的生命。

等單片機(jī)上電開始工作的時(shí)候,雖然C編譯器此時(shí)不在了,但是單片機(jī)都是嚴(yán)格按照C編譯器交代的遺囑開始工作和分配“棧區(qū)”的。因此,“棧區(qū)” 的“臨時(shí)分配” 非真正嚴(yán)格意義上的“臨時(shí)分配”。

函數(shù)內(nèi)部所定義的局部變量總數(shù)不超過(guò)單片機(jī)的“棧” 區(qū)的 RAM 數(shù)量, 那, 萬(wàn)一超過(guò)了“?!?區(qū)的 RAM數(shù)量, 后果嚴(yán)重嗎?

這種情況專業(yè)術(shù)語(yǔ)叫爆棧。程序會(huì)出現(xiàn)莫名其妙的異常,后果特別嚴(yán)重。

為了避免這種情況, 一般在編寫程序的時(shí)候, 函數(shù)內(nèi)部都不能定義大數(shù)組的局部變量, 局部變量的數(shù)量不能定義太多太大,尤其要避免剛才所說(shuō)的定義開辟大數(shù)組局部變量這種情況。

大數(shù)組的定義應(yīng)該定義成全局變量,或者定義成 靜態(tài)的局部變量

有一些C編譯器,遇到“爆?!?的情況,會(huì)好心跟你提醒讓你編譯不過(guò)去,但是也有一些 C 編譯器可能就不會(huì)給你提醒,所以大家以后做項(xiàng)目寫函數(shù)的時(shí)候,要對(duì)爆棧心存敬畏。

全局變量和局部變量的優(yōu)先級(jí)

剛才說(shuō)到,全局變量的作用域是永久性并且不受范圍限制的,而局部變量的作用域就是它所在函數(shù)的內(nèi)部范圍。

那么問題來(lái)了,假如局部變量和全局變量的名字重名了,此時(shí)函數(shù)內(nèi)部執(zhí)行的變量到底是局部變量還是全局變量?

這個(gè)問題就涉及到優(yōu)先級(jí)。

注意,當(dāng)面對(duì)同名的局部變量和全局變量時(shí),函數(shù)內(nèi)部執(zhí)行的變量是局部變量,也就是局部變量在函數(shù)內(nèi)部要比全局變量的優(yōu)先級(jí)高。

我們來(lái)舉一些例子

請(qǐng)看下面第一個(gè)例子

unsignedchara=5;//此處第1個(gè)a是全局變量

voidmain()//主函數(shù)
{
unsignedchara=2;//此處第2個(gè)a是局部變量,跟上面全局變量的第1個(gè)a重名了
print(a);//把a(bǔ)發(fā)送到電腦端的串口助手軟件上觀察
while(1)
{

}
}

正確的答案是 2。在函數(shù)內(nèi)部的局部變量比全局變量的優(yōu)先級(jí)更加高。

雖然這里的兩個(gè)a重名了, 但是它們的內(nèi)存模型不一樣,第1個(gè)全局變量的a是分配在全局?jǐn)?shù)據(jù)區(qū),是具有唯一的地址的,而第2個(gè)局部變量的a是被分配在臨時(shí)的棧區(qū)的,寄生在 main 函數(shù)內(nèi)部。

再看下面第二個(gè)例子

voidfunction(void);//函數(shù)聲明
unsignedchara=5;//此處第1個(gè)a是全局變量

voidfunction(void)//函數(shù)定義
{
 unsigned char a=3;//此處第 2 個(gè) a 是局部變量。
}

voidmain()//主函數(shù)
{
 unsigned char a=2;//此處第 3 個(gè) a 也是局部變量。
function();//子函數(shù)被調(diào)用
print(a);//把 a 發(fā)送到電腦端的串口助手軟件上觀察。
while(1)
{
}
}

正確的答案是2。因?yàn)?,function這個(gè)子函數(shù)是被調(diào)用結(jié)束之后,才執(zhí)行 print(a)的, 就意味函數(shù)內(nèi)部的局部變量(第2個(gè)局部變量 a)是在執(zhí)行 print(a)語(yǔ)句的時(shí)候就消亡不存在了, 所以此時(shí)print(a)的a是第3個(gè)局部變量的a(在 main 函數(shù)內(nèi)部定義的局部變量的 a)。

再看下面第三個(gè)例子

voidfunction(void);//函數(shù)聲明
unsignedchara=5;//此處第1個(gè)a是全局變量

voidfunction(void)//函數(shù)定義
{
unsignedchara=3;//此處第2個(gè)a是局部變量
}

voidmain()//主函數(shù)
{
function();//子函數(shù)被調(diào)用
print(a);//把a(bǔ)發(fā)送到電腦端的串口助手軟件上觀察
while(1)
{
}
}

正確的答案是5。因?yàn)閒unction這個(gè)子函數(shù)是被調(diào)用結(jié)束之后,才執(zhí)行print(a)的,就意味function函數(shù)內(nèi)部的局部變量(第2個(gè)局部變量)是在執(zhí)行function(a)語(yǔ)句的時(shí)候就消亡不存在了。

同時(shí),因?yàn)榇藭r(shí)main函數(shù)內(nèi)部也沒有定義a的局部變量,所以此時(shí)function(a)的a是必然只能是第1個(gè)全局變量的a(在main函數(shù)外面定義的全局變量的a)。

最后

看到本文之后,相信大家已經(jīng)對(duì)棧有了一些基礎(chǔ)的認(rèn)識(shí),在嵌入式編程中,我們也要時(shí)刻注意,避免爆棧;如果有錯(cuò)誤歡迎指出,我們下一期,再見。

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

    關(guān)注

    13

    文章

    4122

    瀏覽量

    85270
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4235

    瀏覽量

    61962
  • 模型
    +關(guān)注

    關(guān)注

    1

    文章

    3031

    瀏覽量

    48346

原文標(biāo)題:從嵌入式編程中感悟「棧」為何方神圣?

文章出處:【微信號(hào):strongerHuang,微信公眾號(hào):strongerHuang】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    labview深入探索------全局變量、局部變量與內(nèi)存管理

    不存在全局變量和局部變量,同樣可以編制規(guī)模很大的程序,這說(shuō)明局部變量全局變量并不是必須的,LV提供了它們是因?yàn)樵谔囟ǖ那闆r下可以簡(jiǎn)化編程。當(dāng)我們使用SUBVI時(shí),我們需要定義一個(gè)連接
    發(fā)表于 07-13 17:49

    LabVIEW結(jié)構(gòu)的使用——全局變量和局部變量

    全局變量和局部變量是LabVIEW用來(lái)傳遞數(shù)據(jù)的工具。LabVIEW編程是一種數(shù)據(jù)流編程,它是通過(guò)連線來(lái)傳遞數(shù)據(jù)的。但是如果一個(gè)程序太復(fù)雜的話,有時(shí)連線會(huì)很困難甚至無(wú)法連接,這時(shí)就需要用到局部變量
    發(fā)表于 02-09 14:46

    LabVIEW編程難點(diǎn)之局部變量全局變量

    最近學(xué)習(xí)Labview,找了3、4本書看,但是對(duì)局部變量全局變量的說(shuō)法不是特別清晰,就此跟大家討論下:Labview中局部變量是在一個(gè)VI中傳遞數(shù)據(jù),如果說(shuō)創(chuàng)建了前面板某個(gè)數(shù)值輸入控件類型為
    發(fā)表于 01-08 20:46

    謹(jǐn)慎使用局部變量全局變量

    局部全局變量是高級(jí)的LabVIEW概念。它們不是LabVIEW數(shù)據(jù)流執(zhí)行模型中固有的部分。使用局部變量全局變量時(shí),程序框圖可能會(huì)變得難以閱讀,因此需謹(jǐn)慎使用。錯(cuò)誤地使用
    發(fā)表于 01-30 10:58

    靜態(tài)變量、全局變量和局部變量

    域。全局變量只需在一個(gè)源文件中定義,就可以作用于所有的源文件。當(dāng)然,其他不包含全局變量定義的源文件需要用extern關(guān)鍵字再次聲明這個(gè)全局變量。2>靜態(tài)局部變量具有
    發(fā)表于 06-20 09:52

    【原創(chuàng)分享】STM32 C語(yǔ)言全局變量和局部變量

    作者:張角老師(張飛實(shí)戰(zhàn)電子高級(jí)工程師)大家好,我們今天來(lái)探討一下C語(yǔ)言的全局變量和局部變量。如果我們想徹底搞清楚這兩個(gè)概念,我們必須回答幾個(gè)問題:第一,C語(yǔ)言為什么要區(qū)分變量的作用域,或者說(shuō)做出
    發(fā)表于 06-17 11:18

    全局變量和局部變量的相關(guān)資料推薦

    一些注意事項(xiàng):全局變量和局部變量重名以后,根據(jù)就近原則,打印會(huì)顯示局部變量的值,可在變量前加入::代表全部變量;應(yīng)減少不必要的全部
    發(fā)表于 12-15 06:10

    編程時(shí)可以用局部變量替代全局變量

    盡量用局部變量替代全局變量。如果用局部變量能實(shí)現(xiàn)功能,最好用局部變量。在函數(shù)僅僅只是要用到某個(gè)全局變量,而無(wú)需改動(dòng)時(shí),就將
    發(fā)表于 02-28 06:22

    static作用(修飾函數(shù)、局部變量、全局變量

    詳細(xì)介紹了static作用(修飾函數(shù)、局部變量、全局變量)的用法
    發(fā)表于 11-17 10:30 ?4次下載

    全局變量和局部變量有什么區(qū)別

    全局變量是編程術(shù)語(yǔ)中的一種,源自于變量之分。變量分為局部全局,局部變量又可稱之為內(nèi)部
    發(fā)表于 12-11 11:58 ?3.2w次閱讀
    <b class='flag-5'>全局變量</b><b class='flag-5'>和局部變量</b>有什么區(qū)別

    LABVIEW初級(jí)教程之局部變量全局變量的示例程序合集免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是LABVIEW初級(jí)教程之局部變量全局變量的示例程序合集免費(fèi)下載
    發(fā)表于 01-16 10:23 ?34次下載
    LABVIEW初級(jí)教程之<b class='flag-5'>局部變量</b>與<b class='flag-5'>全局變量</b>的示例程序合集免費(fèi)下載

    在C語(yǔ)言中,全局變量濫用的后果是什么

    01 啥是全局變量 說(shuō)起全局變量,就不得不提到全局變量局部變量,靜態(tài)全局變量,靜態(tài)局部變量,這
    發(fā)表于 06-24 17:14 ?1606次閱讀

    C語(yǔ)言中局部變量全局變量

    全局變量也稱為外部變量,它是在函數(shù)外部定義的變量。它不屬于哪一個(gè)函數(shù),它屬于一個(gè)源程序文件。其作用域是整個(gè)源程序。在函數(shù)中使用全局變量,一般應(yīng)作全局
    的頭像 發(fā)表于 10-15 10:48 ?5308次閱讀

    詳解LABVIEW中的局部變量全局變量

    本文檔的主要內(nèi)容詳細(xì)介紹的是LABVIEW初級(jí)教程之局部變量全局變量的詳細(xì)資料說(shuō)明。
    發(fā)表于 03-29 15:00 ?26次下載

    Python-局部變量全局變量

    局部變量是在函數(shù)內(nèi)部定義的變量,只能在函數(shù)內(nèi)部使用,函數(shù)執(zhí)行結(jié)束后,函數(shù)內(nèi)部的局部變量會(huì)被系統(tǒng)回收,不同的函數(shù),可以定義相同名稱的局部變量,相互之間沒有任何關(guān)聯(lián)
    的頭像 發(fā)表于 02-16 15:16 ?785次閱讀
    Python-<b class='flag-5'>局部變量</b>與<b class='flag-5'>全局變量</b>