函数体内的局部变量位于栈中还是堆中

函数体内的局部变量是位于栈中。很多人回答时,总是带上堆,回答是在堆栈中,其实是他们没有理解“堆和栈”的意义。

 局部变量位于栈外面,程序可能可以工作,但是肯定会有问题
 

我们首先看启动文件,了解堆和栈的大小,重要的代码部分如下:

; Amount of memory (in bytes) allocated for Stack

; Tailor this value to your application needs

; <h> Stack Configuration

;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>

; </h>

Stack_Size      EQU     0x00000100

                AREA    STACK, NOINIT, READWRITE, ALIGN=3

Stack_Mem       SPACE   Stack_Size

__initial_sp

                                                  

; <h> Heap Configuration

;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>

; </h>

Heap_Size       EQU     0x00000008

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3

__heap_base

Heap_Mem        SPACE   Heap_Size

__heap_limit

从上面代码,我们可以看出:

Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>,意思是栈空间按照8字节对齐;于是它定义 “STACK, NOINIT, READWRITE, ALIGN=3”,即按照2^3=8字节对齐;

“Stack_Size  EQU  0x00000100”表示栈的大小为256个字节;

Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>,意思是堆空间按照8字节对齐;于是它定义 “STACK, NOINIT, READWRITE, ALIGN=3”,即按照2^3=8字节对齐;

“Heap_Size  EQU  0x00000008”表示栈的大小为8个字节;

在非系统的STM32程序中,也就是裸机的STM32程序中,这个堆几乎用不到。即使我们用到动态内存分配,也不会用到。因为我们通常会在RAM中划分出一块存储区用作内存分配,所以还是用不到KEIL划分的堆,因此,我们可以将这个堆设置为8,即堆的大小为8个字节。

下面分析函数体内的声明的数组是位于栈中,代码如下:

#include "stm32f10x.h"

#include "USART1.h"

#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "stdlib.h"

#include <string.h>

u32 STACK_TOP;

void Array_Test1(char *src)

{

         STACK_TOP=__get_MSP();//读取栈指针

         printf("   STACK_TOP3: 0x%x",STACK_TOP);

         *src='A';

}

void Array_Test(void)

{

         char array[40];//占用内存为40个字节

         STACK_TOP=__get_MSP();//读取栈指针

         printf("  STACK_TOP2: 0x%x",STACK_TOP);

  Array_Test1(array);

         STACK_TOP=__get_MSP();//读取栈指针

         printf("  STACK_TOP4: 0x%x",STACK_TOP);

         printf("  array address: 0x%x",array);

}

int main(void)

{

         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4

         USART1_Serial_Interface_Enable(115200);

         printf("\r\nCPU reset\r\n");

         STACK_TOP=__get_MSP();//读取栈指针

         printf("\r\nSTACK_TOP1: 0x%x",STACK_TOP);

         while(1)

         {

           Array_Test();

           STACK_TOP=__get_MSP();//读取栈指针

           printf("\r\nSTACK_TOP1: 0x%x",STACK_TOP);

         }

}

编译成功后,打开“*.map”文件,找到下面的信息:

Symbol Name        Value         Ov Type   Size  Object(Section)

.data                0x20000000   Section    4  main.o(.data)

.data                0x20000004   Section    4  usart1.o(.data)

.data                0x20000008   Section    20  stm32f10x_rcc.o(.data)

APBAHBPrescTable   0x20000008   Data      16  stm32f10x_rcc.o(.data)

ADCPrescTable       0x20000018   Data      4   stm32f10x_rcc.o(.data)

.data               0x2000001c   Section    20  system_stm32f10x.o(.data)

.bss                0x20000030   Section    96  libspace.o(.bss)

HEAP          0x20000090   Section        8  startup_stm32f10x_hd.o(HEAP)

Heap_Mem     0x20000090   Data           8  startup_stm32f10x_hd.o(HEAP)

STACK         0x20000098   Section      256  startup_stm32f10x_hd.o(STACK)

Stack_Mem     0x20000098   Data         256  startup_stm32f10x_hd.o(STACK)

__initial_sp     0x20000198   Data           0  startup_stm32f10x_hd.o(STACK)

从上面的“*.map”文件,我们可以看出:

Heap的起始地址为0x20000090,有8个字节的存储空间;

STACK起始地址为0x20000198结束地址为0x20000098,因为栈是向下生成的,共计有256个字节的存储空间;

通过仿真我们得到下面的信息:

可以看到array[40]的首地址为0x2000016C,由于STACK起始地址为0x20000198结束地址为0x20000098,因此函数体内的数组是位于栈中。如果函数体内的暂态变量比栈空间大,程序一旦运行到这个函数,就会引起死机。因此,不用认为编译都没有问题了,怎么会死机呢。

STACK TOP1: 0x20000198 STACK TOP2: 0x20000168  STACK TOP3: 0x20000160  STACK TOP4:0x20000168 array address: 0x2000016c

0x20000198-0x20000168-8=40

这里减去8,是因为进入Array_Test()函数,需要将PC指针等压入栈中,所以这里要减去8;

在Array_Test()中,声明数组如下:

char array[40];//占用内存为40个字节

通过比对,位于栈中的数组的字节数是正确的,同时数组的地址范围位于栈中。因此,函数体内的声明的局部变量是位于栈中的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值