作者:郑沛坤
无论冯诺伊曼结构还是哈佛结构,都强调了现代计算机以存储器为核心。事实上无论代码和数据运行时都存放在计算机内存中,无论芯片内和芯片外的FLASH、RAM等都要进行统一编址,内存的地址是唯一确认的,理解C程序的内存布局图,有利于理解和调试C程序。
内存布局图;
一个C程序编译时内存分为5大存储区:堆取、栈区、全局区、文字常量区和代码区。
如图是stm32f4的存储器映射图,4G内存的区域被分为8个512M的存储块:代码、SRAM、外设等不同功能的区域。
栈区
栈区分为主栈区和其他栈区,每个函数都有一个独立的栈区,每个不同的栈区就是一个相互独立的作用域,在不同的作用域,变量名可以重复。在执行函数时,函数中的局部变量就保存在栈区,函数调用结束后,CPU会自动释放栈区内存的使用权。
如以下案例1所示,不同的函数区域内,可以定义相同的局部变量名,如func()和main()函数中都定义了相同的局部变量”n”。main()函数中打印值不一定是100的原因,即是CPU自动释放调用函数的栈区内存的使用权并不意味着栈区数据的销毁,栈区内存数据的销毁取决于此块内存是否被其他函数所使用。
1
2
3
4
5
6
7
8
9
10int *func(){
int n = 100;
return &n;
}
int main(){
int *pFunc = func();
int n = *pFunc;
printf("\n value = %d\n",n);
return 0;
}全局区
全局区保存的是全局变量(Global Variable)和静态变量(Static Variable)等,全局区的内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在,由CPU进行分配和善后。
全局变量在声明时没有赋初值时,编译器会将他初始化为0。全局变量的作用域是整个工程,其他文件不能再定义一个与其相同名字的变量,可以使用”extern”外部声明后直接使用。
静态变量由静态全局变量和静态局部变量两种。静态全局变量的作用域小于全局变量,static修饰的全局变量仅对此文件有效,其他文件不可访问,作用域仅在此文件中,解决了其他文件中使用同名变量的冲突,有效的降低了不同程序模块之间的耦合。静态局部变量不同于一般的局部变量,他不存在栈区内存中,保存在全局区内存中,即使函数返回,他的值也能继续保存,如果将案例1中的代码稍加修饰,main()函数中打印值可保证是100。
1
2
3
4
5
6
7
8
9
10int *func(){
static int n = 100;
return &n;
}
int main(){
int *pFunc = func();
int n = *pFunc;
printf("\n value = %d\n",n);
return 0;
}函数的使用方式和全局变量类似,如果用static修饰函数时,即是静态函数。和静态局部变量相似,静态函数只在声明他的文件中可见,其他文件不能引用此静态函数,而可以定义相同函数名的静态函数。
函数名和数组名类似,表明了此函数的地址。
堆区
和栈区内存不同,堆区内存由程序员自己管理,通常在栈区内存空间不足时使用。和栈相比,堆区的好处是内存空间足够大,但同时也有内存空间碎片化、分配效率较低的问题。