-3

我有点困惑存储在计算机内存中的 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();
 }
4

3 回答 3

1

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

您可能应该c先阅读。

于 2012-10-11T18:14:03.363 回答
1

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

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

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

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

等等...

于 2012-10-11T20:17:18.563 回答
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或在文件范围(任何函数之外)声明的变量具有 storage class static,这意味着这些变量的内存在程序启动时分配并保留到程序退出。在块中声明且没有static关键字的变量具有存储类auto,这意味着它们只存在于该块中1avar2不能被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 (0xbffffe4e0)

显然,在这个实现中,具有静态范围的变量gvaravar存储的变量与具有自动范围的变量完全不同,比如avarx

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

   1 .文件“storage.c”
   2.版本“01.01”
   5.文本
   6.Ltext0:
 第165章
 第166章
 第168章 4
 171 克瓦尔:
 172 0000 01000000 .long 1
 第173章 4
 176 变量.0:
 177 0004 02000000 .long 2
 第178章
 第179章 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 .文本
 182 00000000
 182 00000000
 182 00000000
 182 00000000
 第183章 4
 第185章
 187主线:
   1:storage.c **** #include
   2:存储.c ****
   3:storage.c **** int gvar = 1;
   4:存储.c ****
   5:storage.c **** int main(void)
   6:存储.c **** {
 189 .LM1:
 190.LBB2:
 191 0000 55 推升 %ebp
 192 0001 89E5 移动 %esp, %ebp
 193 0003 83EC08 subl $8, %esp
   7:storage.c **** 静态 int svar = 2;
   8:storage.c **** int avar = 3;
 195 .LM2:
 196 0006 C745FC03 移动 $3, -4(%ebp)
 196 000000
   9:存储.c ****
  10:storage.c **** 做{
  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 推力 %eax
 206 001b FF75F8 pushl -8(%ebp)
 207 001e 8D45FC leal -4(%ebp), %eax
 208 0021 50 推力 %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 推力 $gvar
 212 00
 213 0035 FF350000 pushl gvar
 213 0000
 214 003b 68000000 推力 $.LC0
 214 00
 215 0040 E8FCFFFF 调用 printf
 215 法郎
 216 0045 83C430 加价 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:存储.c ****
  19:storage.c **** 返回 0;
 221 .LM6:
 222 0048 B8000000 移动 $0, %eax
 222 00
  20:storage.c **** }
 224 .LM7:
 225 .LBE2:
 226 004d C9 离开
 227 004e C3 RET
 第228章
 第237章
 第239章
 241. 正文:
 242 004f 90 .ident“GCC:(GNU)2.96 20000731(Red Hat Linux 7.2 2.96-112.7.2)”

有很多东西要费力,但它告诉我们为什么我们在内存地址上会出现如此大的差异。

线条

   5.文本
   6.Ltext0:
 第165章
 第166章
 第168章 4
 171 克瓦尔:
 172 0000 01000000 .long 1
 第173章 4
 176 变量.0:
 177 0004 02000000 .long 2

告诉我们 和 的内存gvar位于svar程序.text映像的部分,即程序代码所在的位置。

相比之下,线条

195 .LM2:
 196 0006 C745FC03 移动 $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.注意,这并不一定意味着每次进入和退出块时都会分配和释放内存;通常,相同的内存位置将被重用,但您不能保证它们具有与退出块时相同的值。

于 2012-10-11T20:04:17.333 回答