如何存储c语言变量(在堆栈,列表,树中?)它们存储在哪里?(在ram / hdd中)?

时间:2012-10-11 18:11:36

标签: c memory

我有点困惑如何将c变量存储在计算机的内存中    请解释它们存储的位置以及存储它们的数据结构形式?

 #include<stdio.h>
 #include<conio.h>
 int main(void)
 {
  int r;
  int a,b,c;
  a=10;
  b=20;
   c=30;
 char e=3;
 int f[10]={1,2,3};

  printf("the value of pointers is\n %d\n %d\n %d\n %d\n %d\n %d\n",&a,&b,&c,&e,&f,&r);
  getch();
 }

3 个答案:

答案 0 :(得分:1)

c中有不同的存储类,示例中的存储类存储在堆栈中。

您可能应首先阅读c

答案 1 :(得分:1)

一般来说(我的意思是,因为我在这里写的每个句子都可以找到一个反例),你可以定义的所有C变量都将存储在内存(RAM)中。 不同类型的变量可以保存在不同类型( segment )的内存中。

您编译的C程序位于代码段中。 您在函数中定义的常用变量在程序的堆栈(也是内存)中定义。 使用malloc()等分配的变量。位于(再次,内存)。 除非您写入某个文件,否则磁盘上不会存储任何内容。

现在,我说的是正确的吗?不完全是。 操作系统通过分页机制决定存储在RAM中的内容以及存储在磁盘上的内容。 内存在页面中管理。如果操作系统认为应该将每个页面换出到硬盘驱动器,那么所有变量都可以在该页面中,这意味着它们将存储在磁盘上。 如果稍后需要此内存,操作系统将此页面交换回内存。

同样,这是一般的。 您的操作系统可以禁用分页,在这种情况下,所有内容都将始终在内存中。 您还可以将内存的某些部分映射为磁盘驱动器,在这种情况下,写入此磁盘的所有内容仍保留在内存中。

等等......

答案 2 :(得分:0)

变量存储位置和方式的确切细节取决于实现。语言定义仅指定变量的可见性和生命周期,而不是存储它们的机制。

我们将看一个特定的实现 - 在Red Hat 7.2上的gcc 2.96。

这是一个简单的源文件:

#include <stdio.h>

int gvar = 1;            // file scope, static extent

int main(void)
{
  static int svar = 2;  // block scope, static keyword => static extent
  int avar = 3;         // block scope, auto extent

  do {
    int avar2 = 4;      // block scope, auto extent
    printf("gvar   = %d (%p)\nsvar   = %d (%p)\navar   = %d (%p)\navar2  = %d (%p)\n", 
    gvar, (void *) &gvar,
    svar, (void *) &svar,
    avar, (void *) &avar,
    avar2, (void *) &avar2);
  } while (0);

  return 0;
}

使用关键字static或文件范围(任何函数之外)声明的变量具有存储类static,这意味着这些变量的内存在程序启动时分配并保持到程序退出。在块中声明且没有static关键字的变量具有存储类auto,这意味着它们仅存在于该块 1 中。 avar2循环之外的名称不能引用do,并且不保证在循环退出后保留其值。

我们用

编译程序
gcc -o storage -g storage.c -ansi -pedantic -Wall -Werror -Wa,-aldh=storage.lst.redhat

-Wa,-alhd=...会将生成的机器代码列表写入指定的文件。由于我们添加了-g调试标志,因此原始C源将与机器代码交错。

以下是该计划的输出:

gvar   = 1 (0x80495b0)
svar   = 2 (0x80495b4)
avar   = 3 (0xbfffe4e4)
avar2  = 4 (0xbfffe4e0)

显然,在此实现中,具有静态范围的变量(如gvaravar)存储在与具有自动范围的变量(avarx完全不同的地方。

以下是生成的汇编代码的列表(减去一些分页符):

   1                    .file   "storage.c"
   2                    .version    "01.01"
   5                .text
   6                .Ltext0:
 165                .globl gvar
 166                .data
 168                    .align 4
 171                gvar:
 172 0000 01000000      .long   1
 173                    .align 4
 176                svar.0:
 177 0004 02000000      .long   2
 178                        .section    .rodata
 179                    .align 32
 180                .LC0:
 181 0000 67766172      .string "gvar   = %d (%p)\nsvar   = %d (%p)\nvar   = %d (%p)\navar2  = %d (%p)\n"
 181      2020203D 
 181      20256420 
 181      28257029 
 181      0A737661 
 182 0044 00000000  .text
 182      00000000 
 182      00000000 
 182      00000000 
 182      00000000 
 183                    .align 4
 185                .globl main
 187                main:
   1:storage.c     **** #include 
   2:storage.c     **** 
   3:storage.c     **** int gvar = 1;
   4:storage.c     **** 
   5:storage.c     **** int main(void)
   6:storage.c     **** {
 189                .LM1:
 190                .LBB2:
 191 0000 55            pushl   %ebp
 192 0001 89E5          movl    %esp, %ebp
 193 0003 83EC08        subl    $8, %esp
   7:storage.c     ****   static int svar = 2;
   8:storage.c     ****   int avar = 3;
 195                .LM2:
 196 0006 C745FC03      movl    $3, -4(%ebp)
 196      000000
   9:storage.c     **** 
  10:storage.c     ****   do {
  11:storage.c     ****     int avar2 = 4;
 198                .LM3:
 199                .LBB3:
 200 000d C745F804      movl    $4, -8(%ebp)
 200      000000
  12:storage.c     ****     printf("gvar   = %d (%p)\nsvar   = %d (%p)\nvar   = %d (%p)\navar2  = %d (%p)\n", 
 202                .LM4:
 203 0014 83EC0C        subl    $12, %esp
 204 0017 8D45F8        leal    -8(%ebp), %eax
 205 001a 50            pushl   %eax
 206 001b FF75F8        pushl   -8(%ebp)
 207 001e 8D45FC        leal    -4(%ebp), %eax
 208 0021 50            pushl   %eax
 209 0022 FF75FC        pushl   -4(%ebp)
 210 0025 68040000      pushl   $svar.0
 210      00
 211 002a FF350400      pushl   svar.0
 211      0000
 212 0030 68000000      pushl   $gvar
 212      00
 213 0035 FF350000      pushl   gvar
 213      0000
 214 003b 68000000      pushl   $.LC0
 214      00
 215 0040 E8FCFFFF      call    printf
 215      FF
 216 0045 83C430        addl    $48, %esp
  13:storage.c     ****     gvar, (void *) &gvar,
  14:storage.c     ****     svar, (void *) &svar,
  15:storage.c     ****     avar, (void *) &avar,
  16:storage.c     ****     avar2, (void *) &avar2);
  17:storage.c     ****   } while (0);
 218                .LM5:
 219                .LBE3:
  18:storage.c     **** 
  19:storage.c     ****   return 0;
 221                .LM6:
 222 0048 B8000000      movl    $0, %eax
 222      00
  20:storage.c     **** }
 224                .LM7:
 225                .LBE2:
 226 004d C9            leave
 227 004e C3            ret
 228                .Lfe1:
 237                .Lscope0:
 239                    .text
 241                .Letext:
 242 004f 90            .ident  "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.2)"

这是很多,但它告诉我们为什么我们在内存地址上有这样的差异。

   5                .text
   6                .Ltext0:
 165                .globl gvar
 166                .data
 168                    .align 4
 171                gvar:
 172 0000 01000000      .long   1
 173                    .align 4
 176                svar.0:
 177 0004 02000000      .long   2

告诉我们gvarsvar的内存位于程序代码的.text部分,这是程序代码所在的部分。

比较线

 195                .LM2:
 196 0006 C745FC03      movl    $3, -4(%ebp)
 196      000000
...
 198                .LM3:
 199                .LBB3:
 200 000d C745F804      movl    $4, -8(%ebp)
 200      000000

告诉我们avaravar2的内存相对于当前帧指针(存储在%ebp中); avar存储在距离帧指针偏移4个字节的位置,而avar2存储距离帧指针偏移8个字节。

同样,这就是一个操作系统上的一个编译器的版本所做的事情;不同操作系统上的不同编译器可能使用不同的结构(尽管这种方法非常常见)。

如果你真的很想知道确切的细节,你会想要了解更多关于你的架构(x86 vs. Power vs. MIPS vs ...),你会想要做一些汇编编程。

<小时/> 1。请注意,这并不一定意味着每次进入和退出块时都会分配和释放内存;通常,相同的内存位置将被重用,但您无法保证它们具有与退出块时相同的值。