C语言08 flash存储分配+程序运行内存分配

一、从stm32引入理解

1、MDK编译log:

Program Size: Code=72072  RO-data=6864  RW-data=1316 ZI-data=8684

Code  是存储程序代码的;(删掉代码中未使用的函数等以节省flash空间)

RO-data  是存储const常量和已初始化的字符串等;(类比于文字常量区)

RW-data 是存储可读写的初始化值不为0的全局变量和静态变量;(类比于其他平台的data段,数据保持在bin文件中)

ZI-data  是存储未初始化或者初始化值为0的全局变量和静态变量;未初始化的变量BIN文件只需要记录其大小,等程序运行时在RAM开辟空间。(类比于其他平台的bss段(block started by symbol),data段和bss段又合称为数据区)

=Heap堆= new, malloc手动动态分配的内存,需要手动delete,free释放。如果不释放,只有等程序运行正常结束时,由操作系统回收,理论上无限大。

对大内存的操作,需要放堆区。如C++:

student stu[4*1024*1024] ;会出问题,应改为:student *stu=new stu[4*1024*1024];   释放:delete[] stu;

=stack栈 =程序运行的场景信息(函数的参数,返回值,局部变量)。由操作系统自动分配/释放,空间有限。程序在编译期对变量和函数内存分配都在栈上进行,且程序运行过程中函数调用时参数的传递也在栈上进行。

FLASH大小 = Code + RO-data +RW-data = BIN大小

RAM大小 = RW-data + ZI-data+堆+栈

在stm32的启动.s文件里面,可以根据需要将栈大小设置得大点,堆栈的内存占用是在RAM分配给 RW-data + ZI-data后的地址开始分配的。

=====bss段和data段相关

bss 段: block started by symbol;存放未初始化的全局变量的内存区域;属于静态内存分配。并不给该段的数据分配空间,只是在bin中记录数据所需空间的大小。

data段:存放已初始化的全局变量;属于静态分配,数据保存在目标文件中。

===== stm32f10x的堆栈设置:

startup_stm32f10x_hd.s

======stm32f10x的falsh地址和Ram地址设置:

stm32f10x.h

=========测试验证方法:打印变量的地址

{
    char c = 'a';
    printf("c address is = %p\n", &c);
    char *p1 = &c;
    printf("c address is = 0X%X\n", p1);
 }

1.定义多个全局变量和静态变量,打印查证其地址是否从0x20000000开始,证明全局/静态变量就是从内存首地址开始的。

2.定义const只读变量或者字符串,打印查证其地址是否从0x08000000开头,处于flash区域,说明RO-DATA的确不占用RAM空间

3.定义一个局部变量,打印出其地址,发现是以0x20000000开头的,说明局部变量是处于栈区的。

==============================

二、堆栈相关:

1、内存分栈内存、堆内存、全局变量和静态变量内存。

栈内存类似于栈,一般最多只有1-2M大小,函数内部的一般方式声明的变量都是放在函数的栈内存中,所以太大的数组会栈溢出。全局变量内存一般没有上限,堆内存也没有。所以你可以用全局变量或者动态分配内存(堆内存)

2、堆栈溢出一般是由什么原因导致的?

堆栈溢出一般是循环的递归调用导致的;使用大数据结构的局部变量,也可能导致堆栈溢出;已分配的堆内存未释放导致的内存泄漏,会造成系统内存浪费,系统运行速度减慢甚至崩溃。

3、请问下面程序有什么错误?

{
   int a[60][250][1000],i,j,k;

   for(k=0;k<1000;k++)

    for(j=0;j<250;j++)

     for(i=0;i<60;i++)

      a[i][j][k]=0;
}

答:循环语句内外换一下

(编译的时候没错,运行的时候出错,这个数组太大,如果放在栈中,还是会溢出,要作为全局变量)

==============================

三、存储相关

分析下面的代码:

1、

{
    char s[], char *p2;  //p2,s 都在栈上
    char *p3 = “123456”; //p3在栈上,123456\0 在常量区
    char *p1; 
    p1= (malloc)(10); //p1在栈上,10字节的内存在堆上
    strcpy(p1, “123456”);
    //123456\0 在常量区,编译器可能将它与p3所指向的“123456”优化成—个地方。
    free(p1); //释放掉10字节的堆空间,p1还在,要进行NULL赋值
    p1=NULL;
}

2、

{
    char *a = "hello";
    char *b = "hello";
    if(a==b)
        printf("YES");
    else
        printf("NO");
}

常量字符串"hello"位于静态存储区,它在程序生命期内恒定不变。如果编译器优化的话,会有可能a和b同时指向同一个hello的,则它们地址相同。如果编译器没有优化,那么就是两个不同的地址,则不同。对VC,是相同。

3、写出并解释下列代码的输出结果:

{
    char str1[] = "abc";  
    char str2[] = "abc";
    const char str3[] = "abc";  
    const char str4[] = "abc";
    const char *str5 = "abc";
    const char *str6 = "abc";
    char *str7 = "abc";
    char *str8 = "abc";
    
    cout << ( str1 == str2 ) << endl;    
    cout << ( str3 == str4 ) << endl;
    cout << ( str5 == str6 ) << endl;
    cout << ( str7 == str8 ) << endl;
}

解答:结果是:0 0 1 1

str1,str2,str3,str4是数组变量,它们有各自的内存空间;

而str5,str6,str7,str8是指针,它们指向相同的常量区域,编译器优化节省内存。

4、指针和数组的空间分配

    分为两种情况:

    第一,如果是全局的和静态的

    char *p = “hello”;

    这是定义了一个指针,指向rodata section里面的“hello”,可以被编译器放到字符串池。在汇编里面的关键字为.ltorg。意思就是在字符串池里的字符串是可以共享的,这也是编译器优化的一个措施。

    char a[] = “hello”;

    这是定义了一个数组,分配在可写数据块,不会被放到字符串池。

    第二,如果是局部的

    char *p = “hello”;

    这是定义了一个指针,指向rodata section里面的“hello”,可以被编译器放到字符串池。在汇编里面的关键字为.ltorg。意思就是在字符串池里的字符串是可以共享的,这也是编译器优化的一个措施。另外,在函数中可以返回它的地址,也就是说,指针是局部变量,但是它指向的内容是全局的。

    char a[] = “hello”;

    这是定义了一个数组,分配在堆栈上,初始化由编译器进行。(短的时候直接用指令填充,长的时候就从全局字符串表拷贝),不会被放到字符串池(同样如前,可能会从字符串池中拷贝过来)。注意不应该返回它的地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值