我正在关注"C Primer Plus">一书,遇到了一个理解记忆区域的问题。在书中,它指出:
通常,程序对静态对象、自动对象和动态分配的对象使用不同的内存区域。示例 12.15 说明了这一点。
// where.c -- where's the memory?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int static_store = 30;
const char * pcg = "String Literal";
int main(void)
{
int auto_store = 40;
char auto_string[] = "Auto char Array";
int *pi;
char *pcl;
pi = (int *) malloc(sizeof(int));
*pi = 35;
pcl = (char *) malloc(strlen("Dynamic String") + 1);
strcpy(pcl, "Dynamic String");
printf("static_store: %d at %pn", static_store, &static_store);
printf(" auto_store: %d at %pn", auto_store, &auto_store);
printf(" *pi: %d at %pn", *pi, pi);
printf(" %s at %pn", pcg, pcg);
printf(" %s at %pn", auto_string, auto_string);
printf(" %s at %pn", pcl, pcl);
printf(" %s at %pn", "Quoted String", "Quoted String");
free(pi);
free(pcl);
return 0;
}
运行代码并获取:
static_store: 30 at 0x10a621040
auto_store: 40 at 0x7ffee55df768
*pi: 35 at 0x7fbf1d402ac0
String Literal at 0x10a620f00
Auto char Array at 0x7ffee55df770
Dynamic String at 0x7fbf1d402ad0
Quoted String at 0x10a620f9b
这本书的结论是:
如您所见,静态数据(包括字符串文本(占用一个区域,自动数据占用第二个区域,动态分配的数据占用第三个区域(通常称为内存堆或可用存储(。
我可以弄清楚他们的地址不同。我如何确保他们来自不同的地区?
不同的地区有非常不同的地址。如果它们位于同一区域,则它们将具有相似的地址。更好的例子,我们在每个区域中分配 2 个对象:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int stack1;
int stack2;
static int bss1;
static int bss2;
static int data1=1;
static int data2=1;
int* heap1 = malloc(1);
int* heap2 = malloc(1);
char* rodata1 = "hello";
char* rodata2 = "world";
printf(".stackt%p %pn", &stack1, &stack2);
printf(".bsst%p %pn", &bss1, &bss2);
printf(".datat%p %pn", &data1, &data2);
printf(".heapt%p %pn", heap1, heap2);
printf(".rodatat%p %pn", rodata1, rodata2);
free(heap1);
free(heap2);
}
输出(例如(:
.stack 000000000022FE2C 000000000022FE28
.bss 0000000000407030 0000000000407034
.data 0000000000403010 0000000000403014
.heap 0000000000477C50 0000000000477C70
.rodata 0000000000404000 0000000000404006
如您所见,同一段中的两个变量具有几乎相同的地址,唯一的区别是对象的大小(可能还有一些对齐空间(。虽然与其他段中的变量相比,它们的地址非常不同。
C 标准规定,一个对象可以有 4 种不同的存储持续时间之一。 这些是:
- 静态的
- 自动
- 分配
- 线
上面的代码解决了其中的前 3 个问题。
静态对象是使用static
修饰符在文件范围或本地范围声明的。 字符串文本也是静态对象。
一个自动对象,通常称为局部变量,它在函数或封闭范围内声明。
分配的对象是其内存由分配函数(如malloc
(返回的对象。
实际上,编译器通常会将这些对象类型中的每一种放在不同的内存区域中。 静态对象通常放置在可执行文件的数据部分,自动(读取:本地(对象通常存储在堆栈上,分配的对象通常存储在堆上。
特别是字符串文本是静态对象,通常放置在标记为只读的数据部分的特殊部分中。
这些区域通常位于不同的内存区域中,但并非必须如此。 因此,虽然在实践中,每个区域中的对象地址会明显不同,但它们并不是必需的。
因此,您实际上不需要"确保"不同类型的变量位于不同的区域。 编译器会根据您定义它们的方式为您处理这个问题。
可能有助于获得为程序分配的实际部分的是 nm 命令,例如,您可以在那里看到static_store偏移量。
static_store: 30 at 0x600b00
==>0000000000600b00 D static_store
在coliru上观看直播:http://coliru.stacked-crooked.com/a/1b45e01f508ec7b7
请注意附加的 nm 命令:gcc main.cpp && ./a.out && nm a.out
但是,您必须记住,您通常在具有 MMU 的系统上,因此虚拟内存地址映射到实际内存。
查找更多信息,例如 https://www.embeddedrelated.com/showarticle/900.php
我想尝试用更简单的方式解释这一点。
0x...
是一个十六进制字符串,表示二进制位字符串。你可以把它想象成代表一个数字,但速记是因为你不需要知道这个数字,只是它与其他类似编码数字的相对值。所以这意味着"地址值"实际上只是一个数字。
为什么要用数字来表示内存位置?因为出于所有意图和目的,内存只是一个非常大的字节数组,其值可以通过索引读取。C 在逻辑上(不是物理上(将此内存阵列划分为不同的部分以实现高效存储。因此,内存中 2 个地址位置越接近,它们在该字节数组表示形式中的距离就越近。
任何应用程序可用的地址范围都是在运行时确定的,实际上不是特定内存空间的任何部分。因此,平心而论,没有理由确定某些项目位于某个内存区域中。只是在内存中靠近的 2 个对象位于不同的区域在统计上是非常不可信的。