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

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

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

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

棧是一種LIFO后入先出的什么數(shù)據(jù)結(jié)構(gòu)?

lhl545545 ? 來源:玩轉(zhuǎn)單片機(jī) ? 作者:玩轉(zhuǎn)單片機(jī) ? 2020-06-09 09:26 ? 次閱讀

沒有比這個(gè)更直觀的啦,棧是一種受限的數(shù)據(jù)結(jié)構(gòu)模型,其數(shù)據(jù)總是只能在頂部追加,利用一個(gè)指針進(jìn)行索引,頂端叫棧頂,相對(duì)的一端底部稱為棧底。棧是一種LIFO后入先出的數(shù)據(jù)結(jié)構(gòu)。

棧就兩種操作:

PUSH,壓棧,向棧內(nèi)加入數(shù)據(jù),

POP,出棧

再進(jìn)一步探討:

首先將棧與堆分清,從看到這篇文章開始,我建議你不要把堆和棧連在一起叫,棧是棧,堆是堆,這是兩回事,別混為一談!(堆本文不深入討論)

從C/C++編程語(yǔ)言的角度來看:

相同點(diǎn):都是一片內(nèi)存區(qū),在鏈接時(shí)指定棧區(qū)/堆區(qū)的位置以及大小。

不同點(diǎn):

棧:由編譯器分配,存放函數(shù)的參數(shù)值,局部變量,寄存器組(不同的單片機(jī)/處理器各有不同)、函數(shù)調(diào)用參數(shù)傳遞、中斷異常產(chǎn)生時(shí)須保存處理器狀態(tài)的寄存器值等

堆:由程序員分配釋放,對(duì)于C而言,malloc、realloc/free進(jìn)行分配/釋放,對(duì)C++而言,由new/delete分配/釋放。

為啥用

棧這個(gè)數(shù)據(jù)模型的應(yīng)用價(jià)值是什么呢?先來看一下單片機(jī)內(nèi)部的可能有哪些棧應(yīng)用?以STM32為例,參考IAR C/C++ Development Guide,P207

處理器模式建議段名描述

SupervisorSVC_STACK操作系統(tǒng)

IRQIRQ_STACK通用(IRQ)中斷處理程序的堆棧。

FIQFIQ_STACK用于高速(FIQ)中斷處理程序的堆棧。

UndefinedUND_STACK堆棧用于未定義的指令中斷。支持硬件協(xié)處理器和指令集擴(kuò)展的軟件仿真

AbortABT_STACK用于指令獲取和數(shù)據(jù)訪問存儲(chǔ)器中止中斷處理程序的堆棧。

如果使用RTOS還有任務(wù)棧,如果是Linux,其內(nèi)核線程同樣也需要棧的支持,等等這一切的一切棧,其本質(zhì)上都是利用了棧數(shù)據(jù)模型的LIFO后入先出的特性,一個(gè)典型應(yīng)用場(chǎng)景就是比如做一件事情做到一半而要轉(zhuǎn)而去做另外一件事,對(duì)于芯片編程而言,就需要將當(dāng)前的工作做個(gè)暫存,等另外一件事情做完了,再接著回來繼續(xù)做。那么怎么做到呢,以一個(gè)中斷處理為例,要記住當(dāng)前的工作態(tài)有哪些信息需要暫存呢?PC指針,局部變量等就被壓入棧,再將中斷服務(wù)程序地址導(dǎo)入PC指針,進(jìn)而去執(zhí)行中斷服務(wù)程序,待中斷處理完畢,在將棧里的內(nèi)容按照后入先出彈出到對(duì)應(yīng)的寄存器就恢復(fù)了原程序的現(xiàn)場(chǎng),進(jìn)而繼續(xù)執(zhí)行。

怎么用

棧在哪里定義大小,定多大合適?這可能很多剛接觸單片機(jī)開發(fā)的同學(xué)不是太清楚,下面就將比較常見的IAR開發(fā)環(huán)境為例如何定義棧定義棧大小的地方說明一下,這里以IAR8.4.1為例,有兩種方式可以進(jìn)行棧大小設(shè)置。

IDE設(shè)置

為了更加清楚明了,制作了一個(gè)GIF操作展示視頻,在stack/heap中就可以設(shè)置了,其中stack用于設(shè)置棧區(qū)大小,heap用于設(shè)置堆大小。

這個(gè)demo中設(shè)置了其棧的大小為0x200,堆的大小為0x400,全編譯后,檢查map文件就印證了棧/堆的大小如預(yù)期所修改。

鏈接配置文件

其實(shí)對(duì)于比較熟悉的開發(fā)人員,上一種方式并非推薦用法。用鏈接配置文件將具有更好的靈活性,比如可以指定一個(gè)段的對(duì)齊方式,存儲(chǔ)位置,某個(gè)符號(hào)的存儲(chǔ)位置等等。這里同樣為了直觀也做了一個(gè)GIF動(dòng)畫,介紹如何通過鏈接文件進(jìn)行棧/堆的大小配置。

其最終的效果也一樣如預(yù)期將棧區(qū)的大小設(shè)置好了。

棧溢出

這里為了比較容易的展示棧溢出的問題,在main函數(shù)利用遞歸方法計(jì)算階乘,代碼如下:

#include 《stdio.h》

#include “main.h”

static uint32_t spSatte[200];

static uint32_t spIndex = 0;

/*為什么要用浮點(diǎn)數(shù),因?yàn)閿?shù)據(jù)非常大整型很快就會(huì)溢出*/

float factorial(uint32_t n)

uint32_t sp = __get_MSP

/*記錄棧指針的變化情況*/

spSatte[spIndex++] = sp;

if(n==0 || n==1)

return 1;

else

return (float)n*factorial(n-1);

int main(void)

float x = 0;

uint32_t n = 20;

printf(“stack test:

x = factorial(n);

/*打印棧指針變化情況*/

for(int i = 0;i《spIndex;i++)

printf(“MSP-》%08X

spSatte[i]);

/*打印階乘結(jié)果*/

printf(“factorial(%d)=%f

n,x);

while (1)

為方便觀察,將stm32f407xx_flash.icf 將棧改為256字節(jié)

/*stm32f407xx_flash.icf 將棧改為256字節(jié)*/

define symbol __ICFEDIT_size_cstack__ = 0x200;

define symbol __ICFEDIT_size_heap__ = 0x200;

全編譯后通過map文件來看下棧/堆的分配情況:

“P2”, part 3 of 3: 0x400

CSTACK 0x2000‘05d8 0x200 《Block》

CSTACK uninit 0x2000’05d8 0x200 《Block tail》

HEAP 0x2000‘07d8 0x200 《Block》

HEAP uninit 0x2000’07d8 0x200 《Block tail》

- 0x2000‘09d8 0x400

直觀些,翻譯成下圖,CSTACK段分配在0x2000 0280-0x2000 0480,堆分配在0x2000 0480-0x2000 0680。

棧是一種LIFO后入先出的什么數(shù)據(jù)結(jié)構(gòu)?

圖為什么沒有將0x2000 07D8畫在棧區(qū)呢?通過調(diào)試發(fā)現(xiàn),這個(gè)字空間沒有用做棧的實(shí)際存儲(chǔ)。將工程設(shè)置成simulation模式,debug進(jìn)入main.o勾選掉,我們來計(jì)算20的階乘,來具體看一下:

棧是一種LIFO后入先出的什么數(shù)據(jù)結(jié)構(gòu)?

對(duì)這個(gè)動(dòng)圖解讀一下:

進(jìn)入復(fù)位是,SP_main為0x200007D8,指向棧底,為空棧。那么這是怎么實(shí)現(xiàn)的呢?

__vector_table ;向量表

DCD sfe(CSTACK) ;這條命令會(huì)將程序的CSTACK起始地址裝載給SP_main

DCD Reset_Handler ; Reset Handler復(fù)位向量

前面說0x200007D8并沒有用到,怎么證明呢,在函數(shù)進(jìn)入mian時(shí),第一次壓棧的情況如下:

棧是一種LIFO后入先出的什么數(shù)據(jù)結(jié)構(gòu)?

可見STM32棧的增長(zhǎng)方向是向下增長(zhǎng)的,也即頂在小地址端一側(cè)

棧存儲(chǔ)元素是四字節(jié)對(duì)齊的,因?yàn)镾TM32的字長(zhǎng)是字節(jié),如果深入想想,如果不是司字節(jié)對(duì)齊會(huì)怎么樣?留給感興趣的思考一下。

0x200007D8--0x200007DB 這個(gè)字存儲(chǔ)單元并不是棧的有效存儲(chǔ)空間。

棧的變化情況:

stack test:

MSP-》200007A8

MSP-》20000790

MSP-》20000778

MSP-》20000760

MSP-》20000748

MSP-》20000730

MSP-》20000718

MSP-》20000700

MSP-》200006E8

MSP-》200006D0

MSP-》200006B8

MSP-》200006A0

MSP-》20000688

MSP-》20000670

MSP-》20000658

MSP-》20000640

MSP-》20000628

MSP-》20000610

MSP-》200005F8

MSP-》200005E0

factorial(20)=2432902023163674771.785700 /*結(jié)算結(jié)果與用計(jì)算器一致*/

每調(diào)用一次階乘函數(shù),棧就壓入4個(gè)字,由上面還可以看到第20次進(jìn)入時(shí),棧指針為0x200005E0,如果再壓入4個(gè)字棧指針會(huì)變成0x200005C8,是這樣嗎,結(jié)果還對(duì)嗎?將n改為21編譯運(yùn)行,來看一看:

看到了吧,驚喜來了,棧溢出了,程序已經(jīng)不聽話了,完全不知道在干嘛了。所以棧溢出的后果是極端危險(xiǎn)的,完全無法預(yù)期,程序會(huì)帶來什么后果。

總結(jié)一下

棧是一種LIFO后入先出的數(shù)據(jù)結(jié)構(gòu)模型,是C/C++程序運(yùn)行時(shí)基礎(chǔ),沒這個(gè)棧,C/C++玩不轉(zhuǎn)

棧在嵌入式編程領(lǐng)域隨處可見,比如C棧,中斷棧、異常棧、任務(wù)棧等等,但其基本工作原理都一樣。支持兩種基本數(shù)據(jù)操作:壓棧、出棧。

棧溢出程序的結(jié)果無法預(yù)期,所以合理的設(shè)置棧區(qū)大小是個(gè)永恒的話題,過大則浪費(fèi)內(nèi)存,過小則程序會(huì)飛。

嵌入式編程遞歸函數(shù)要慎用,個(gè)人建議不用。比如IEC61508 功能安全標(biāo)準(zhǔn)中強(qiáng)行規(guī)定不可使用遞歸函數(shù)。

STM32中__get_MSP可以得到當(dāng)前棧指針的值,據(jù)此可以做一定程度的棧溢出保護(hù)措施。防止程序跑飛。

通過上面遞歸調(diào)用測(cè)試,還可以得到一個(gè)啟示,嵌入式編程函數(shù)嵌套的層級(jí)不宜過深,過深則需要相對(duì)較大的棧開銷。
責(zé)任編輯:pj

聲明:本文內(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)投訴
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    hart協(xié)議的協(xié)議結(jié)構(gòu)分析

    的智能化水平,同時(shí)保持與現(xiàn)有模擬系統(tǒng)的兼容性。 2. HART協(xié)議概述 HART協(xié)議可以分為幾個(gè)層次,每個(gè)層次負(fù)責(zé)不同的功能: 2.1 物理層(Physical Layer) 物理層負(fù)責(zé)在物理媒介上傳輸數(shù)據(jù)。HART協(xié)議使用
    的頭像 發(fā)表于 12-02 09:43 ?399次閱讀

    DDC264配置寄存器數(shù)據(jù)寫入和320 DCLK時(shí)鐘脈沖的回讀數(shù)據(jù)結(jié)構(gòu)是什么?

    配置寄存器數(shù)據(jù)寫入和320 DCLK時(shí)鐘脈沖的回讀數(shù)據(jù)結(jié)構(gòu)是什么? 根據(jù)注和表9,16位配置寄存器數(shù)據(jù),4位修訂ID, 300位校驗(yàn)?zāi)J剑趺纯赡苡?024 TOTAL READ
    發(fā)表于 11-19 07:58

    視覺軟件HALCON的數(shù)據(jù)結(jié)構(gòu)

    在研究機(jī)器視覺算法之前,我們需要先了解機(jī)器視覺應(yīng)用中涉及的基本數(shù)據(jù)結(jié)構(gòu)。Halcon數(shù)據(jù)結(jié)構(gòu)主要有圖像參數(shù)和控制參數(shù)兩類參數(shù)。圖像參數(shù)包括:image、region、XLD,控制參數(shù)包括:string、integer、real、handle、tuple數(shù)組等。
    的頭像 發(fā)表于 11-14 10:20 ?580次閱讀
    視覺軟件HALCON的<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>

    何為Teable多維表格數(shù)據(jù)庫(kù),它僅僅是個(gè)在線的智能表格嗎?

    維表格是一種創(chuàng)新的數(shù)據(jù)管理和協(xié)作工具,它結(jié)合了傳統(tǒng)電子表格的直觀界面與關(guān)系數(shù)據(jù)庫(kù)的強(qiáng)大功能。用戶不僅可以像在Excel中樣在二維表格內(nèi)記錄和編輯數(shù)
    的頭像 發(fā)表于 10-14 16:13 ?602次閱讀

    嵌入式環(huán)形隊(duì)列與消息隊(duì)列的實(shí)現(xiàn)原理

    嵌入式環(huán)形隊(duì)列,也稱為環(huán)形緩沖區(qū)或循環(huán)隊(duì)列,是一種先進(jìn)先出(FIFO)的數(shù)據(jù)結(jié)構(gòu),用于在固定大小的存儲(chǔ)區(qū)域中高效地存儲(chǔ)和訪問數(shù)據(jù)。其主要特點(diǎn)包括固定大小的數(shù)組和兩個(gè)指針(頭指針和尾指針
    的頭像 發(fā)表于 09-02 15:29 ?694次閱讀

    嵌入式常用數(shù)據(jù)結(jié)構(gòu)有哪些

    在嵌入式編程中,數(shù)據(jù)結(jié)構(gòu)的選擇和使用對(duì)于程序的性能、內(nèi)存管理以及開發(fā)效率都具有重要影響。嵌入式系統(tǒng)由于資源受限(如處理器速度、內(nèi)存大小等),因此對(duì)數(shù)據(jù)結(jié)構(gòu)的選擇和使用尤為關(guān)鍵。以下是嵌入式編程中常用的幾種數(shù)據(jù)結(jié)構(gòu),結(jié)合具體特點(diǎn)和
    的頭像 發(fā)表于 09-02 15:25 ?648次閱讀

    鴻蒙語(yǔ)言基礎(chǔ)類庫(kù):ohos.util.Deque 線性容器Deque

    Deque(double ended queue)根據(jù)循環(huán)隊(duì)列的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn),符合先進(jìn)先出以及先進(jìn)出的特點(diǎn),支持兩端的元素插入和移除。Deque會(huì)根據(jù)實(shí)際需要?jiǎng)討B(tài)調(diào)整容量,每次進(jìn)行兩倍擴(kuò)容。
    的頭像 發(fā)表于 07-10 09:19 ?280次閱讀
    鴻蒙語(yǔ)言基礎(chǔ)類庫(kù):ohos.util.Deque 線性容器Deque

    rup是一種什么模型

    部分)開發(fā)的,它基于統(tǒng)建模語(yǔ)言(UML)和面向?qū)ο蟮能浖_發(fā)方法。RUP提供了一種結(jié)構(gòu)化的方法來開發(fā)軟件,它包括系列的階段、迭代和里程碑,以確保軟件開發(fā)過程的順利進(jìn)行。 RUP的起
    的頭像 發(fā)表于 07-09 10:13 ?1424次閱讀

    請(qǐng)問esp event的時(shí)序邏輯是怎樣的?

    的.在個(gè)模塊里, 如果notify A再notify B, 回調(diào)的執(zhí)行順序是先進(jìn)入cb_B, 再進(jìn)入cb_A, 看上去是個(gè)先出
    發(fā)表于 06-07 06:57

    OpenHarmony語(yǔ)言基礎(chǔ)類庫(kù)【@ohos.util.Queue (線性容器Queue)】

    Queue的特點(diǎn)是先進(jìn)先出,在尾部增加元素,在頭部刪除元素。根據(jù)循環(huán)隊(duì)列的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)。
    的頭像 發(fā)表于 04-27 21:20 ?383次閱讀
    OpenHarmony語(yǔ)言基礎(chǔ)類庫(kù)【@ohos.util.Queue (線性容器Queue)】

    OpenHarmony語(yǔ)言基礎(chǔ)類庫(kù)【@ohos.util.Deque (線性容器Deque)】

    Deque(double ended queue)根據(jù)循環(huán)隊(duì)列的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn),符合先進(jìn)先出以及先進(jìn)出的特點(diǎn),支持兩端的元素插入和移除。Deque會(huì)根據(jù)實(shí)際需要?jiǎng)討B(tài)調(diào)整容量,每次進(jìn)行兩倍擴(kuò)容。
    的頭像 發(fā)表于 04-25 21:17 ?252次閱讀
    OpenHarmony語(yǔ)言基礎(chǔ)類庫(kù)【@ohos.util.Deque (線性容器Deque)】

    探索編程世界的七大數(shù)據(jù)結(jié)構(gòu)

    結(jié)構(gòu)就像是顆倒掛的小樹,有根、有枝、有葉。它是一種非線性的數(shù)據(jù)結(jié)構(gòu),以層級(jí)的方式存儲(chǔ)數(shù)據(jù),頂部是根節(jié)點(diǎn),底部是葉節(jié)點(diǎn)。
    的頭像 發(fā)表于 04-16 12:04 ?448次閱讀

    物聯(lián)數(shù)據(jù)網(wǎng)關(guān)是什么?

    物聯(lián)數(shù)據(jù)網(wǎng)關(guān)就是物聯(lián)網(wǎng)智能網(wǎng)關(guān)。 物聯(lián)數(shù)據(jù)網(wǎng)關(guān)是物聯(lián)網(wǎng)架構(gòu)中的重要組件之。它是連接物聯(lián)網(wǎng)設(shè)備和云平臺(tái)的中間設(shè)備,負(fù)責(zé)將物聯(lián)網(wǎng)設(shè)備采集到
    的頭像 發(fā)表于 03-29 17:10 ?378次閱讀

    TASKING編譯器是否可以將數(shù)據(jù)結(jié)構(gòu)設(shè)置為 \"打包\"?

    TASKING 編譯器是否可以將數(shù)據(jù)結(jié)構(gòu)設(shè)置為 \"打包\"? GCC 很早以前就提供了這種可能性,可以將__attribute__((packed))與對(duì)齊指令結(jié)合使用。 對(duì)于
    發(fā)表于 03-05 06:00

    矢量與柵格數(shù)據(jù)結(jié)構(gòu)各有什么特征

    數(shù)據(jù)結(jié)構(gòu)是使用點(diǎn)、線和面等基本幾何圖形來描述和表示地理對(duì)象的一種方法。它們由離散的幾何對(duì)象和與之相關(guān)的屬性數(shù)據(jù)組成。矢量數(shù)據(jù)中的點(diǎn)表示個(gè)特
    的頭像 發(fā)表于 02-25 15:06 ?2794次閱讀
    主站蜘蛛池模板: 色秀网站 | 天堂资源吧 | 在线电影天堂 | 中文字幕一区二区三区四区五区 | 色女人网 | 思思99re66在线精品免费观看 | 国产免费午夜 | 日本免费不卡视频一区二区三区 | 深爱五月综合网 | 日本在线观看永久免费网站 | 男人在线网站 | 在线看一区二区 | 性xxx无遮挡 | 超级香蕉97视频在线观看一区 | 青草悠悠视频在线观看 | 精品精品国产自在久久高清 | 黄免费看 | 亚洲大成色www永久网址 | 久久久噜久噜久久gif动图 | 亚洲午夜视频在线 | 韩国三级理在线视频观看 | 欧美操bb | 女人张开腿给男人桶爽免费 | 久久婷婷丁香 | www 在线播放| 视频一区二区在线播放 | 色婷婷激婷婷深爱五月老司机 | 中文字幕天堂 | 亚洲国产精品乱码一区二区三区 | 男男宿舍高h炒肉bl 男男污肉高h坐便器调教 | 亚洲综合激情丁香六月 | 久久天天躁狠狠躁狠狠躁 | 奇米7777影视| 香港经典a毛片免费观看爽爽影院 | 综合婷婷 | 国产成人一区二区在线不卡 | 欧美成年网站 | 一区二区在线观看高清 | 最新版天堂资源官网 | 亚洲永久网站 | 亚洲一区二区免费在线观看 |