使用keil编译工程,分析不同的变量存放的数据段;
代码工程如下
#include <stdio.h>
#include <stdlib.h>
static char dujunqiu_static_data[64] = {1,2,3}; // 已初始化非0 的静态变量,存放 .data段
static char dujunqiu_static_data_zero[32] = {0}; // 已初始化为0 的静态变量,存放 .bss段
static char dujunqiu_static_data_uninit[32]; // 未初始化 的静态变量, 存放 .bss段
char dujunqiu_data[32] = {1,2,3}; // 已初始化非0 的全局变量,存放 .data段
char dujunqiu_bss[64]; // 未初始化 的静态变量, 存放 .bss段
int main(void)
{
char *dujunqiu_const1="hello-1 world"; // 字符串常量区, 存放只读区
char dujunqiu_const2[222]="hello-2 world"; // 字符串常量区, 存放只读区
char dujunqiu_const3[333]={0}; // 临时数据变量,存放栈上
printf("str=%s--%s %d\n", dujunqiu_const1, dujunqiu_const2,dujunqiu_const3[0]);
printf("str=%d %d \n", dujunqiu_data[0], dujunqiu_bss[0]);
return 0;
}
网上搜索一下定义
段名 | 说明 |
---|---|
.constdata | 只读常量数据段,属于RO-data。 |
.text | 代码段。用来存放程序执行代码的内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读。也有可能包含一些只读的常数变量,例如字符串常量等。 |
.data | 数据段。data 段用于存储已经赋初值(非零)的全局变量,且变量占有实际的内存空间。本段的内容由程序初始化,因此会占用exe文件空间。 |
.bss | 数据段,Block Started by Symbol。bss段用于存储未赋初值的全局变量和静态局部变量,这些变量在程序运行前会被初始化为0或NULL。另外,初始化为零的全局变量和静态局部变量也会存储在bss中的数据不分配实际的空间,只体现为一个占位符,只记录数据所需空间的大小,因此不会占用exe文件空间。bss段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在data段后面。 |
heap | 堆。用于存放运行中被动态分配的内存段,可动态扩张或缩减。例如,malloc分配的内存就在堆上。 |
stack | 栈。用于存放程序临时创建的局部变量,即:函数括弧“{}”中定义的临时变量。注意,不包括用static声明的变量,static声明的变量存储在data段中。当函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。 |
全局变量
map文件截图示例,全局变量的存放位置应该是比较清晰的,搜素一下关键字就可以直接查询到;
map文件里面分为本地符号"Local Symbols" 和 全局符号"Global Symbols",所以行号不是连续的;
字符串常量
根据编辑的.bin文件,可以识别到hello-1和hello-2字段;
对比map文件的起始地址记录,两个都是只读区RO;不过一个是code类型,一个是date类型;(前面有几个其它数据,起始地址没有完全对齐)
并且0xde=222,刚好和代码里面的数组长度对上了
进一步搜索关键字 222
map文件刚好可以搜索到一个222长度的数据,在 constdata段
找不到333长度的字段,说明 "dujunqiu_const3"在 stack上,运行时候才会分配;
注意:
1:以上是基于keil编译代码进行map文件分析,不同的编译器可能存在不同的编译策略,最好以实测为准;
2:C语言将字符串字面量存放在常量区是为了保证其不可变性、提高内存效率,并兼容历史设计。实际编程中,如果需要修改字符串,应使用字符数组或堆内存。
3:字符数组(如char s[] = “abc”;)会将字符串拷贝到栈或全局区,是可修改的。(比如 dujunqiu_const2)
动态分配的字符串(如char *s = malloc(4); strcpy(s, “abc”);)存放在堆上。