1.前言不废话,先上示例代码uint8_tnum_byte[4];uint32_tnum_word;constuint32_tnum_word_const=0x1234;uint32_t*point_heap;intmain(void){uint8_tnum_byte_stack;staticuint8_tnum_byte_static;int3_t(*)malloc(4);*point_heap=0x3421;free(point_heap);num_byte_stack=0x11;#pragmasection="CSTACK"char*pbeginstk=__section_begin("CSTACK");#pragmasection="HEAP"char*pbeginheap=__section_begin("HEAP");printf("CSTACKaddris0x%x\r\n",pbeginstk);printf("HEAPaddris0x%x\r\n",pbeginheap);printf("num_byteaddris0x%x\r\n",&num_byte);printf("num_wordaddris0x%x\r\n",&num_word);printf("num_word_constaddris0x%x\r\n",&num_word_const);printf("point_heapaddris0x%x\r\n",&point_heap);printf("point_heapis0x%x\r\n",point_heap);printf("num_byte_stackaddris0x%x\r\n",&num_byte_stack);printf("num_byte_staticaddris0x%x\r\n",&num_byte_static);}打印如下STACKaddris0x20000320HEAPaddris0x20000720num_byteaddris0x20000308num_wordaddris0x2000030cnum_word_constaddris0x8002a44point_heapaddris0x20000310point_heapis0x20000728num_byte_stackaddris0x200006f8num_byte_staticaddris0x20000318先说结论:num_byte、num_word、num_byte_static和point_heap存储在内部RAM中num_byte_stack存贮在栈中。Thememoryrequestedbypoint_heapisintheheap.num_word_const在内部闪存中。如果有同学知道这一点,他们可以出去左转。如果有同学有兴趣,可以往下看。2.大小端由于后面的内容涉及到大小端问题,所以先说一下大小端问题。大端:数据的高位字节存放在地址的低端;低位字节存放在地址的高位;Little-endian:数据的高位字节存放在high-endAddresslow-end;例如:数据0x12345678存储格式big-endian格式低地址<----0x12|0x34|0x56|0x78---->高地址little-endian格式低地址<----0x78|0x56|0x34|0x12---->高地址中的地址一般由编译器分配,也可以在程序中指定。从上表可以清楚的看出,大小端是以字节为单位存储数据的方式。bigendian通俗的理解就是从左到右赋值;小端是从右到左。我们常用的X86结构是小端模式,而KEILC51是大端模式。很多ARM和DSP都是小端模式,本文使用的平台STM32F207就是小端模式。3.一步步分析如果有同学对这部分不是很熟悉,建议先看我之前的推文《C语言的内存分配》,先熟悉一下C语言中栈和内存的概念。先说栈。下面的代码可以在IAR平台下打印出STM32的栈起始位置。#pragmasection="CSTACK"char*pbeginstk=__section_begin("CSTACK");#pragmasection="HEAP"char*pbeginheap=__section_begin("HEAP");打印结果如下:STACKaddris0x20000320HEAPaddris0x20000720地址是否正确?我们可以在IAR中调试的时候,使用Disassembly窗口来查看。关于栈的大小,如下,可以发现栈的结束位置是0x20000720,堆的结束位置是0x20000920。注意:这里的计算涉及到大小端的问题。通过计算:栈的大小=0x20000720-0x20000320=0x400。堆的大小=0x20000920-0x20000720=0x200。这与我们在IAR中的堆栈配置相同。接下来说一下在内存中分配的变量。通过打印可以看出num_byte、num_word、num_byte_static和point_heap不在栈中,它们是存放在内部RAM中的。使用“反汇编”窗口查看以下内容。这也验证了static关键字。当在函数中修改局部变量时,这个变量会像全局变量一样存储在内部ram中。同时也说明STM32内部分配内存时,先分配全局变量(以及static修饰的局部变量),再分配栈,最后分配堆。对于栈的内存分配,局部变量,即num_byte_stack存放在栈的作用域内。num_byte_stackaddris0x200006f8它的地址空间在栈中。因为代码中num_byte_stack=0x11;使用反汇编窗口检查相应的地址值是否为0x11。关于堆栈,我再说一件事。堆栈不仅保存了局部变量,还保存了函数切换和中断发生时的场景,保存了ARM内核的寄存器。这部分我会另外写一篇文章专门讲。堆的问题,简单来说:malloc申请的内存在堆中。point_heap指针指向的内存地址在堆的范围内。*point_heap=point_heapis0x20000728代码中的0x3421;在反汇编窗口中,对应的地址值为0x3421。最后一个num_word_const,const修饰的变量存放在内部flash中,其地址在内部flash的范围内。代码中也有对应的赋值操作,constuint32_tnum_word_const=0x1234;在反汇编窗口中,对应的地址值为0x1234。
