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

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

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

在MCU編程中局部變量賦初始值的重要性

jf_pJlTbmA9 ? 來源:瑞薩MCU小百科 ? 作者:瑞薩MCU小百科 ? 2023-10-16 18:29 ? 次閱讀

C語言編程過程中,由于計算需要,會使用各種各樣的變量,用于給需要訪問的地址取個名稱,方便編程中使用,代碼維護(hù)者也容易理解。

這里先給大家分享一個案例,讓大家意識到變量賦初始值的重要性。

某用戶在基于瑞薩MCU:RA6T2做開發(fā)時,發(fā)現(xiàn)一個問題,MCU發(fā)出的CAN數(shù)據(jù)幀總是莫名其妙的出錯,比如應(yīng)用中明明只使用了CAN的擴(kuò)展幀,但是使用捕捉工具總是能捕捉到遠(yuǎn)程幀,出現(xiàn)遠(yuǎn)程幀的情況毫無規(guī)律可言,有時添加一個定時器中斷,該現(xiàn)象就不會出現(xiàn)了,有時修改了代碼里某處跟CAN沒有任何關(guān)系的代碼,該問題又會出現(xiàn),過了兩周時間調(diào)試無果。在介入Debug時發(fā)現(xiàn),他使用的是CAN擴(kuò)展幀,擴(kuò)展幀使用29位ID標(biāo)識符,而且對ID區(qū)數(shù)據(jù)定義了一個如下結(jié)構(gòu)體:

wKgaomUD5XKAKA7FAAAHACC9mOU044.png

他在需要發(fā)送CAN幀時,申請一個如上結(jié)構(gòu)體的臨時變量can_id,在把can_id.id賦值后,再把該變量的地址傳遞給CAN的發(fā)送函數(shù),在發(fā)送函數(shù)里使用如下語句把id的數(shù)據(jù)寫入CAN的發(fā)送消息緩沖寄存器

wKgaomUD5XOAApX2AAAHaPYEckQ954.png

如下圖,其中第30位的0表示數(shù)據(jù)幀,并不是遠(yuǎn)程幀,31位的1表示擴(kuò)展幀。

wKgZomUD5XWAca2cAADiCZqaiwY457.png

用戶是把can_id的所有數(shù)據(jù)賦值給了CFDTMID0寄存器,假如can_id.dummy中第二個位是1,會有什么后果呢?CFDTMID0.TMRTR=1,即CAN會發(fā)送遠(yuǎn)程幀。

用戶又問:我沒有給dummy賦值啊,為什么dummy的第二個位會變成1呢?這就是問題所在了,就是因為他沒有給can_id.dummy賦值,所以can_id.dummy有可能為任意的值。下面詳細(xì)分析一下,為什么這個局部變量的值會隨意變化。

大家知道,變量根據(jù)存儲類型和用途,一般可以分成:全局變量和局部變量。全局變量,就是指分配了固定地址的變量,全局變量可以在整個代碼范圍內(nèi)使用。我們在申請全局變量時,有時對它賦一個初始值,也時也不會賦初始值,在代碼上可能看不出有什么區(qū)別,但是編譯器在編譯程序時,是區(qū)別對待他們的。對于有初始化的變量,編譯器還需要在Code Flash里(代碼存儲區(qū))分配一段空間,把變量的初始值全部存儲在該區(qū)域里,并且在MCU的啟動代碼里插入一段程序,把這些Code Flash區(qū)的初始值拷貝到變量對應(yīng)的RAM地址中。假如上面的can_id是全局變量,并且申明變量的同時并按下圖賦初始值:

wKgaomUD5XeAaBPmAAAqgT5kmag262.jpg

這時can_id.dummy=0,如果代碼中用戶沒有再賦值,它的值也不會變化,這樣就不會發(fā)生用戶的那個遠(yuǎn)程幀的問題了。對于沒有賦初始值的全局變量,編譯器只是分配RAM的地址,并不會修改RAM地址里的數(shù)據(jù),那么這個變量的值就會依賴于MCU啟動時RAM里的值了。為了避免未賦值的全局變量出現(xiàn)上述的問題,我們一般會在MCU啟動代碼里插入未賦初始值全局變量的清零操作,相當(dāng)于做了一個未賦初始值的全局變量的初始化賦值操作。

像上面的案例,can_id申請的是局部變量,這又是什么情況呢?

因為MCU的RAM資源有限,為了最大限度的利用RAM,MCU會提前分配一塊RAM區(qū)域,叫堆棧區(qū),這塊區(qū)域大家共用,對于只需要在某個函數(shù)內(nèi)使用的變量,引入了局部變量概念。在開始執(zhí)行該函數(shù)時,才從堆棧里分配地址給局部變量使用,函數(shù)執(zhí)行結(jié)束后,該變量占用的RAM區(qū)域被堆?;厥眨?dāng)下次再調(diào)用該函數(shù),再重新分配RAM。因此對于局部變量,每次申請到的地址是不同的,該地址很可能是其它函數(shù)使用過并改寫數(shù)據(jù)了的,因此每次函數(shù)調(diào)用時can_id.dummy的數(shù)據(jù)是不確定的。因為堆棧區(qū)里的數(shù)據(jù)是被反復(fù)利用的,即使MCU的初始化代碼對堆棧區(qū)域做清零處理,也是沒有意義的。

由此看來,局部變量在申請的時候賦一個初始值,是非常有必要的。雖然有時候賦初始值沒有用,但是出現(xiàn)問題時常常是致命的,而且也是非常難以定位的,你可能覺得我的代碼里后面肯定會賦值的,但是后面維護(hù)該項目的其他工程師并不一定意識到這一點。像類似上面的案例,我在其他用戶當(dāng)中也是經(jīng)常見到的。因此軟件工程師在編程的時候,一定要養(yǎng)成局部變量賦初始值的習(xí)慣。

來源:瑞薩MCU小百科
免責(zé)聲明:本文為轉(zhuǎn)載文章,轉(zhuǎn)載此文目的在于傳遞更多信息,版權(quán)歸原作者所有。本文所用視頻、圖片、文字如涉及作品版權(quán)問題,請聯(lián)系小編進(jìn)行處理

審核編輯 黃宇

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

    關(guān)注

    146

    文章

    16796

    瀏覽量

    349330
  • CAN
    CAN
    +關(guān)注

    關(guān)注

    57

    文章

    2686

    瀏覽量

    462909
  • 編程
    +關(guān)注

    關(guān)注

    88

    文章

    3543

    瀏覽量

    93465
  • 變量
    +關(guān)注

    關(guān)注

    0

    文章

    608

    瀏覽量

    28286
收藏 人收藏

    評論

    相關(guān)推薦

    求助,ADC接地的重要性?

    ADC接地的重要性
    發(fā)表于 06-04 07:56

    論RISC-V的MCU中UART接口的重要性

    的適用重要性。某些應(yīng)用場景中,只需要異步通信能力的UART接口就能滿足需求,從而簡化了系統(tǒng)設(shè)計和實現(xiàn)。 綜上所述,RISC-V的MCU中UART接口的
    發(fā)表于 05-27 15:52

    局部變量超出堆棧范圍,想把占用內(nèi)存多的變量申請在全局如何做?

    目前局部變量超出堆棧范圍,現(xiàn)在想把占用內(nèi)存多的變量申請在全局,如何做
    發(fā)表于 03-20 08:03

    C語言中的三種形式變量

    局部變量一個函數(shù)、代碼塊內(nèi)部聲明的變量,只能被該函數(shù)或者代碼塊內(nèi)部應(yīng)用。局部變量函數(shù)之外不可用。
    發(fā)表于 03-11 17:34 ?375次閱讀
    C語言中的三種形式<b class='flag-5'>變量</b>

    多核單片機(jī)中,靜態(tài)局部變量需要劃分分段信息嗎?如何放到函數(shù)對應(yīng)核的ram中?

    請問多核單片機(jī)中,靜態(tài)局部變量需要劃分分段信息嗎?如何放到函數(shù)對應(yīng)核的ram中?
    發(fā)表于 02-06 06:29

    TC275在內(nèi)存分段預(yù)警處理之后,設(shè)置的全局變量初始值不正確怎么解決?

    大家好想問一下,tc275里,自己地圖文件里定義有了新的存檔段,又設(shè)置了首地位置,段內(nèi)對象可寫,4字節(jié)對齊。但是在內(nèi)存分段預(yù)警處理之后,設(shè)置的全局變量初始值不正確,板子上電后會給出一個隨機(jī)
    發(fā)表于 01-22 06:40

    編程三相交流電源重要性和優(yōu)勢

    編程三相交流電源重要性和優(yōu)勢? 可編程三相交流電源是現(xiàn)代電源技術(shù)中的一項重要發(fā)展。它能夠提供高質(zhì)量、可靠的交流電源,并具有多種可編程功能。
    的頭像 發(fā)表于 01-04 15:29 ?567次閱讀

    LTC2943初始化的時候要如何確定Qlsb的初始值呢?

    最近公司使用一款LTC2943的庫侖計,但是初始化的時候要如何確定Qlsb的初始值呢?或者可以提供一個STM32作為MCU的例程最好。
    發(fā)表于 01-04 06:47

    變量的聲明和定義有什么區(qū)別和聯(lián)系

    內(nèi)存空間并指定一個標(biāo)識符或名稱以及數(shù)據(jù)類型。定義變量時,需要指定變量的類型以及它的初始值(可選)。變量的定義通常包括關(guān)鍵字(如int、float等)和
    的頭像 發(fā)表于 12-07 16:14 ?945次閱讀

    C語言編程時,各種類型的變量該如何初始化?

    C語言編程時,各種類型的變量該如何初始化? C語言中,每個變量都需要在使用之前進(jìn)行初始化。
    的頭像 發(fā)表于 12-07 13:53 ?1048次閱讀

    jvm配置堆內(nèi)存初始值參數(shù)

    程序中,堆內(nèi)存的初始值是非常重要的,它決定了程序在運行過程中能夠使用的內(nèi)存大小。因此,優(yōu)化JVM性能的過程中,對于堆內(nèi)存初始值的合理配置是至關(guān)重要
    的頭像 發(fā)表于 12-05 14:17 ?677次閱讀

    python變量命名規(guī)則

    的規(guī)則和約定。本文將詳盡、詳實、細(xì)致地探討Python變量的命名規(guī)則,幫助讀者了解如何正確命名變量并在編程中遵循最佳實踐。 一、變量命名規(guī)則的重要性
    的頭像 發(fā)表于 11-23 15:44 ?1122次閱讀

    for循環(huán)里的變量局部變量

    對于一個普通for循環(huán)而言,循環(huán)變量局部變量。大多數(shù)編程語言中,循環(huán)變量循環(huán)內(nèi)部的作用域
    的頭像 發(fā)表于 11-23 14:50 ?2208次閱讀

    全局變量初始值,是在哪里賦值的?

    data段data_ram的初始化內(nèi)容就是從data_rom來,而data_rom是從__DATA_ROM來。 那么,__DATA_ROM是什么東西,從哪里呢? 搜一搜工程里面的代碼,很簡單,這是從ld文件來
    發(fā)表于 10-27 10:18 ?828次閱讀
    全局<b class='flag-5'>變量</b>的<b class='flag-5'>初始值</b>,是在哪里賦值的?

    嵌入式全局變量初始化原理詳解

    全局變量初始值,是在哪里賦值的?
    的頭像 發(fā)表于 10-27 10:15 ?1039次閱讀
    嵌入式全局<b class='flag-5'>變量</b>的<b class='flag-5'>初始</b>化原理詳解