我有点困惑如何将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();
}
答案 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)
显然,在此实现中,具有静态范围的变量(如gvar
和avar
)存储在与具有自动范围的变量(avar
和x
完全不同的地方。
以下是生成的汇编代码的列表(减去一些分页符):
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
告诉我们gvar
和svar
的内存位于程序代码的.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
告诉我们avar
和avar2
的内存相对于当前帧指针(存储在%ebp
中); avar
存储在距离帧指针偏移4个字节的位置,而avar2
存储距离帧指针偏移8个字节。
同样,这就是一个操作系统上的一个编译器的版本所做的事情;不同操作系统上的不同编译器可能使用不同的结构(尽管这种方法非常常见)。
如果你真的很想知道确切的细节,你会想要了解更多关于你的架构(x86 vs. Power vs. MIPS vs ...),你会想要做一些汇编编程。
<小时/> 1。请注意,这并不一定意味着每次进入和退出块时都会分配和释放内存;通常,相同的内存位置将被重用,但您无法保证它们具有与退出块时相同的值。