欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C程序中Ubuntu、stm32的內(nèi)存分配問題

 更新時間:2021年12月23日 16:03:09   作者:Lc-Yusheng  
這篇文章主要介紹了C程序中Ubuntu、stm32的內(nèi)存分配問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一、內(nèi)存分區(qū)概念介紹

1.1、C/C++編譯程序的內(nèi)存占用

1、棧區(qū)(stack)
由編譯器自動分配釋放,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。
2、堆區(qū)(heap)
一般由程序員分配釋放,若程序員不釋放,程序結(jié)束時可能由OS回收 。它與數(shù)據(jù)結(jié)構(gòu)中的堆不同,分配方式類似于鏈表。
3、全局區(qū)(靜態(tài)區(qū))(static)
全局變量和靜態(tài)變量的存儲是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量、未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。當程序結(jié)束后,變量由系統(tǒng)釋放 。
4、文字常量區(qū)
存放常量字符串。當程序結(jié)束后,常量字符串由系統(tǒng)釋放 。
5、程序代碼區(qū)
存放函數(shù)體的二進制代碼。

1、從靜態(tài)存儲區(qū)域分配。內(nèi)存在程序編譯的時候就已經(jīng)分配好,這塊內(nèi)存在程序的整個運行期間都存在。例如全局變量,static變量。

2、在棧上創(chuàng)建。在執(zhí)行函數(shù)時,函數(shù)內(nèi)局部變量的存儲單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時這些存儲單元自動被釋放。棧內(nèi)存分配運算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。
3、從堆上分配,亦稱動態(tài)內(nèi)存分配。程序在運行的時候用malloc或new申請任意多少的內(nèi)存,程序員自己負責在何時用free或delete釋放內(nèi)存。動態(tài)內(nèi)存的生存期由程序員決定,使用非常靈活,但如果在堆上分配了空間,就有責任回收它,否則運行的程序會出現(xiàn)內(nèi)存泄漏,頻繁地分配和釋放不同大小的堆空間將會產(chǎn)生堆內(nèi)碎塊。

1.2、棧和堆、全局/靜態(tài)存儲區(qū)和常量存儲區(qū)的對比

1、棧區(qū): 主要用來存放局部變量, 傳遞參數(shù), 存放函數(shù)的返回地址。.esp 始終指向棧頂, 棧中的數(shù)據(jù)越多, esp的值越小。

2、堆區(qū): 用于存放動態(tài)分配的對象, 當你使用 malloc和new 等進行分配時,所得到的空間就在堆中。動態(tài)分配得到的內(nèi)存區(qū)域附帶有分配信息, 所以你能夠 free和delete它們。

3、數(shù)據(jù)區(qū): 全局,靜態(tài)和常量是分配在數(shù)據(jù)區(qū)中的,數(shù)據(jù)區(qū)包括bss(未初始化數(shù)據(jù)區(qū))和初始化數(shù)據(jù)區(qū)。 ?

注意: 堆向高內(nèi)存地址生長; 棧向低內(nèi)存地址生長; 堆和棧相向而生,堆和棧之間有個臨界點,稱為stkbrk。

1.3、圖片說明

?

補充:

Stack: 棧,存放Automatic Variables,按內(nèi)存地址由高到低方向生長,其最大大小由編譯時確定,速度快,但自由性差,最大空間不大。
Heap: 堆,自由申請的空間,按內(nèi)存地址由低到高方向生長,其大小由系統(tǒng)內(nèi)存/虛擬內(nèi)存上限決定,速度較慢,但自由性大,可用空間大。
每個線程都會有自己的棧,但是堆空間是共用的。

參考文獻:https://www.icode9.com/content-1-772915.html?

?二、C語言編程論證

1.1、Ubuntu測試代碼實現(xiàn)

1、main.c:

#include <stdio.h>
#include <stdlib.h>
//定義全局變量
int init_global_a = 1;
int uninit_global_a;
static int inits_global_b = 2;
static int uninits_global_b;
void output(int a)
{
	printf("hello");
	printf("%d",a);
	printf("\n");
}
 
int main( )
{   
	//定義局部變量
	int a=2;
	static int inits_local_c=2, uninits_local_c;
    int init_local_d = 1;
    output(a);
    char *p;
    char str[10] = "lyy";
    //定義常量字符串
    char *var1 = "1234567890";
    char *var2 = "qwertyuiop";
    //動態(tài)分配
    int *p1=malloc(4);
    int *p2=malloc(4);
    //釋放
    free(p1);
    free(p2);
    printf("棧區(qū)-變量地址\n");
    printf("                a:%p\n", &a);
    printf("                init_local_d:%p\n", &init_local_d);
    printf("                p:%p\n", &p);
    printf("              str:%p\n", str);
    printf("\n堆區(qū)-動態(tài)申請地址\n");
    printf("                   %p\n", p1);
    printf("                   %p\n", p2);
    printf("\n全局區(qū)-全局變量和靜態(tài)變量\n");
    printf("\n.bss段\n");
    printf("全局外部無初值 uninit_global_a:%p\n", &uninit_global_a);
    printf("靜態(tài)外部無初值 uninits_global_b:%p\n", &uninits_global_b);
    printf("靜態(tài)內(nèi)部無初值 uninits_local_c:%p\n", &uninits_local_c);
    printf("\n.data段\n");
    printf("全局外部有初值 init_global_a:%p\n", &init_global_a);
    printf("靜態(tài)外部有初值 inits_global_b:%p\n", &inits_global_b);
    printf("靜態(tài)內(nèi)部有初值 inits_local_c:%p\n", &inits_local_c);
    printf("\n文字常量區(qū)\n");
    printf("文字常量地址     :%p\n",var1);
    printf("文字常量地址     :%p\n",var2);
    printf("\n代碼區(qū)\n");
    printf("程序區(qū)地址       :%p\n",&main);
    printf("函數(shù)地址         :%p\n",&output);
    return 0;
}

2、使用命令創(chuàng)建一個 main.c 文件:

gedit main.c

3、復制粘貼上述代碼

4、編譯執(zhí)行

gcc main.c -o main

./main

5、結(jié)果展示

?

分析說明:可以從上圖可以得出棧區(qū)內(nèi)存地址由高到低方向生長,堆區(qū)內(nèi)存地址由低到高方向生長。而且整個程序的內(nèi)存也是從高到低的地址進行分配的。?

?1.2、STM32驗證代碼實現(xiàn)

打開之前做過的串口通訊實驗代碼,在其中進行修改,后面我也會給出先關(guān)串口鏈接

1、代碼更改

修改bsp_usart.h :

添加頭文件:

#include <stdio.h>
#include <stdlib.h>

?修改bsp_usart.c :

重寫 fputc 函數(shù):

int fputc(int ch, FILE *f)
{
	USART_SendData(DEBUG_USARTx, (uint8_t)ch);
	
	while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
	
	return (ch);
}

main.c?:?

#include "stm32f10x.h"
#include "bsp_usart.h"  //添加 bsp_usart.h 頭文件
 
int init_global_a = 1;
int uninit_global_a;
static int inits_global_b = 2;
static int uninits_global_b;
 
void output(int a)
{
	printf("hello");
	printf("%d",a);
	printf("\n");
}
 
int main(void)
{	
	//定義局部變量
	int a=2;
	static int inits_local_c=2, uninits_local_c;
	int init_local_d = 1;
	char *p;
	char str[10] = "lyy";
	//定義常量字符串
	char *var1 = "1234567890";
	char *var2 = "qwertyuiop";
	//動態(tài)分配
	int *p1=malloc(4);
	int *p2=malloc(4);
	USART_Config();//串口初始化
	output(a);
	//釋放
	free(p1);
	free(p2);
	printf("棧區(qū)-變量地址\n");
	printf("                a:%p\n", &a);
	printf("                init_local_d:%p\n", &init_local_d);
	printf("                p:%p\n", &p);
	printf("              str:%p\n", str);
	printf("\n堆區(qū)-動態(tài)申請地址\n");
	printf("                   %p\n", p1);
	printf("                   %p\n", p2);
	printf("\n全局區(qū)-全局變量和靜態(tài)變量\n");
	printf("\n.bss段\n");
	printf("全局外部無初值 uninit_global_a:%p\n", &uninit_global_a);
	printf("靜態(tài)外部無初值 uninits_global_b:%p\n", &uninits_global_b);
	printf("靜態(tài)內(nèi)部無初值 uninits_local_c:%p\n", &uninits_local_c);
	printf("\n.data段\n");
	printf("全局外部有初值 init_global_a:%p\n", &init_global_a);
	printf("靜態(tài)外部有初值 inits_global_b:%p\n", &inits_global_b);
	printf("靜態(tài)內(nèi)部有初值 inits_local_c:%p\n", &inits_local_c);
	printf("\n文字常量區(qū)\n");
	printf("文字常量地址     :%p\n",var1);
	printf("文字常量地址     :%p\n",var2);
	printf("\n代碼區(qū)\n");
	printf("程序區(qū)地址       :%p\n",&main);
	printf("函數(shù)地址         :%p\n",&output);
	return 0;
}

2、編譯輸出

3、燒錄

打開串口調(diào)試助手,打開串口后,按一下 RESET 鍵,顯示結(jié)果:

?4、分析說明

? ?與Ubuntu一樣,stm32的棧區(qū)的地址值是從上到下減小的,堆區(qū)則是從上到下增長的。從每個區(qū)來看,地址值是從上到下逐步減小的,即棧區(qū)的地址是高地址,代碼區(qū)的地址是處于低地址。

1.3、keil下stm32存儲觀察

stm32數(shù)據(jù)的存儲位置

1、RAM(隨機存取存儲器)
存儲的內(nèi)容可通過指令隨機讀寫訪問。RAM中的存儲的數(shù)據(jù)在掉電是會丟失,因而只能在開機運行時存儲數(shù)據(jù)。其中RAM又可以分為兩種,一種是Dynamic RAM(DRAM動態(tài)隨機存儲器),另一種是Static RAM(SRAM,靜態(tài)隨機存儲器)。棧、堆、全局區(qū)(.bss段、.data段)都是存放在RAM中。
2、ROM(只讀存儲器)
只能從里面讀出數(shù)據(jù)而不能任意寫入數(shù)據(jù)。ROM與RAM相比,具有讀寫速度慢的缺點。但由于其具有掉電后數(shù)據(jù)可保持不變的優(yōu)點,因此常用也存放一次性寫入的程序和數(shù)據(jù),比如主版的BIOS程序的芯片就是ROM存儲器。代碼區(qū)和常量區(qū)的內(nèi)容是不允許被修改的,所以存放于ROM中。

查看:

分析說明:

? ? 從圖片中可以看出ROM的地址分配是從0x8000000開始,整個大小為0x40000,這個部分用于存放代碼區(qū)和文字常量區(qū)。RAM的地址分配是從0x20000000開始,其大小是0xC000,這個區(qū)域用來存放棧、堆、全局區(qū)(.bss段、.data段)。與代碼結(jié)果顯示進行對比,也可以看出對應得部分得地址與設置的是相對應的。?

三、總結(jié)

? ?通過對C語言程序里全局變量、局部變量、堆、棧等概念的重溫以及在不同平臺進行編程驗證,熟悉掌握了C語言中相關(guān)概念,并對整體的內(nèi)存地址分配由高到低,以及棧區(qū)內(nèi)存地址由高到低方向生長,堆區(qū)內(nèi)存地址由低到高方向生長進行了驗證。經(jīng)過本次實驗,主要是對C程序的內(nèi)存分配有進一步的認識,知道一個C程序內(nèi)存應該包括哪些部分。其中,主要是程序段、數(shù)據(jù)段、堆棧三個部分。不同系統(tǒng)下面,區(qū)域內(nèi)的地址值變化是不相同??偟膩碚f,是對內(nèi)存的分配有了比較新的認識。

四、參考資料

https://blog.csdn.net/qq_43279579/article/details/110308101

https://blog.csdn.net/ssj925319/article/details/110727925?spm=1001.2014.3001.5501?

USART串口通信:

鏈接: https://pan.baidu.com/s/1YspOK2I3Ddm5XntKXKRnXA

提取碼: emev?

到此這篇關(guān)于C程序中Ubuntu、stm32的內(nèi)存分配問題的文章就介紹到這了,更多相關(guān)C程序Ubuntu、stm32的內(nèi)存分配內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入C++中struct與class的區(qū)別分析

    深入C++中struct與class的區(qū)別分析

    本篇文章是對C++中struct與class的區(qū)別進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • c++先序二叉樹的構(gòu)建詳解

    c++先序二叉樹的構(gòu)建詳解

    在本篇文章里小編給大家分享了關(guān)于c++先序二叉樹的構(gòu)建的相關(guān)知識點,需要的朋友們跟著學習下。
    2019-04-04
  • C語言實現(xiàn)電腦關(guān)機程序

    C語言實現(xiàn)電腦關(guān)機程序

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)電腦關(guān)機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • C++之Qt5雙緩沖機制案例教程

    C++之Qt5雙緩沖機制案例教程

    這篇文章主要介紹了C++之Qt5雙緩沖機制案例教程,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++無法重載點符號、::、sizeof等的原因

    C++無法重載點符號、::、sizeof等的原因

    這篇文章主要介紹了C++無法重載點符號、::、sizeof等的原因的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • 老程序員教你一天時間完成C語言掃雷游戲

    老程序員教你一天時間完成C語言掃雷游戲

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)掃雷游戲初級版,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • OpenCV實現(xiàn)馬賽克功能

    OpenCV實現(xiàn)馬賽克功能

    這篇文章主要為大家詳細介紹了OpenCV實現(xiàn)馬賽克功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C++11中的chrono庫詳解

    C++11中的chrono庫詳解

    C++11提供了日期時間相關(guān)的庫chrono,通過chrono庫可以很方便的處理日期和時間,這篇文章主要介紹了C++11中的chrono庫,需要的朋友可以參考下
    2023-03-03
  • C++設計模式之抽象工廠模式

    C++設計模式之抽象工廠模式

    這篇文章主要介紹了C++設計模式之抽象工廠模式,本文要講的抽象工廠模式,就是工廠方法模式的擴展和延伸,需要的朋友可以參考下
    2014-09-09
  • C語言進度條的實現(xiàn)原理詳解

    C語言進度條的實現(xiàn)原理詳解

    這篇文章主要介紹了C語言進度條的實現(xiàn)原理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08

最新評論