程序对静态对象,自动对象和动态分配的对象使用不同的内存区域

时间:2018-10-17 13:09:19

标签: c

我正在关注《 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

这本书的结论:

  

如您所见,包括字符串文字在内的静态数据占一个区域,自动数据占第二个区域,动态分配的数据占第三个区域(通常称为内存堆或空闲存储)。

我可以确定它们的地址不同。我怎么能保证他们位于不同的地区?

4 个答案:

答案 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个对象位于不同区域在统计上是不可信的。