我正在关注《 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 %p\n", static_store, &static_store);
printf(" auto_store: %d at %p\n", auto_store, &auto_store);
printf(" *pi: %d at %p\n", *pi, pi);
printf(" %s at %p\n", pcg, pcg);
printf(" %s at %p\n", auto_string, auto_string);
printf(" %s at %p\n", pcl, pcl);
printf(" %s at %p\n", "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
这本书的结论:
如您所见,包括字符串文字在内的静态数据占一个区域,自动数据占第二个区域,动态分配的数据占第三个区域(通常称为内存堆或空闲存储)。
我可以确定它们的地址不同。我怎么能保证他们位于不同的地区?
答案 0 :(得分:18)
不同区域的地址非常不同。如果他们在同一地区,他们将有相似的地址。更好的例子是,我们在每个区域分配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(".stack\t%p %p\n", &stack1, &stack2);
printf(".bss\t%p %p\n", &bss1, &bss2);
printf(".data\t%p %p\n", &data1, &data2);
printf(".heap\t%p %p\n", heap1, heap2);
printf(".rodata\t%p %p\n", rodata1, rodata2);
free(heap1);
free(heap2);
}
输出(例如):
.stack 000000000022FE2C 000000000022FE28
.bss 0000000000407030 0000000000407034
.data 0000000000403010 0000000000403014
.heap 0000000000477C50 0000000000477C70
.rodata 0000000000404000 0000000000404006
如您所见,同一段中的两个变量具有几乎相同的地址,唯一的区别是对象的大小(可能还有对齐的空间)。与其他段中的变量相比,它们的地址截然不同。
答案 1 :(得分:9)
C standard声明一个对象可以具有4个不同的存储持续时间之一。这些是:
上面的代码处理了其中的前3个。
使用static
修饰符在文件范围或本地范围声明了静态对象。字符串文字也是静态对象。
自动对象,通常称为局部变量,它在函数或封闭范围内声明。
已分配对象是其对象由分配函数(例如malloc
)返回的对象。
在实践中,编译器通常会将这些对象类型的每一个放置在不同的内存区域中。静态对象通常放置在可执行文件的数据部分中,自动(读取:本地)对象通常存储在堆栈中,分配的对象通常存储在堆中
尤其是字符串文字是静态对象,通常放在标记为只读的数据节的特殊部分。
这些区域通常位于不同的内存区域中,但是不是必须如此。因此,尽管实际上每个区域中对象的地址会明显不同,但并不一定要如此。
因此,您实际上不必“确保”不同类型的变量位于不同的区域。编译器会根据您定义它们的方式为您解决这些问题。
答案 2 :(得分:1)
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
上答案 3 :(得分:0)
我想尝试以更简单的方式对此进行解释。
0x...
是一个十六进制字符串,代表一串二进制位。您可以认为它代表一个数字,但是因为您不需要知道数字,只是它相对于其他类似编码数字的相对值,所以可以简化表示。因此,这意味着“地址值”实际上只是一个数字。
为什么要使用数字来表示存储位置?因为出于所有目的和目的,内存只是一个非常大的字节数组,可以通过索引读取其值。 C在逻辑上(而非物理上)将此内存阵列划分为不同的部分,以进行有效存储。因此,内存中2个地址位置越近,在该字节数组表示中它们就越靠近。
可用于任何应用程序的地址范围是在运行时确定的,实际上并不是特定内存空间的任何部分。因此,公平地说,没有理由确定某些项是否位于某个内存区域中。只是在内存上靠近在一起的2个对象位于不同区域在统计上是不可信的。