静态变量的地址相同,但局部变量

时间:2015-08-03 08:05:11

标签: c memory memory-management operating-system

我正在尝试学习操作系统。目前我在虚拟寻址。什么书说如果我们有一个static variable和一个local variable并且我们更新它们并睡眠一段时间并尝试打印它们的地址,那么在多个这样的进程中运行一个将获得相同的内存地址。

这是因为每个进程都感觉它具有整个内存并且无法控制物理内存,因此在同时运行的各个进程中地址将保持相同。我理解这一点,但是当我运行我的程序时,我在静态变量中获得相同的地址,但在局部变量中有所不同。凭借我的小操作系统知识,我无法理解为什么会发生这种情况。这是我的代码

int staticvar = 0;

int main(int argc, char const *argv[])
{
  int localvar = 0;
  staticvar += 1;
  localvar += 1;
  sleep(10);
  printf("static address: %x, value: %d\n", &staticvar, staticvar );
  printf("static address: %x, value: %d\n", &localvar, localvar );
  return 0;
}

当我同时运行三个不同的进程时,这是我的输出。

./a.out 
static address: 60104c, value: 1
static address: 67c6128c, value: 1

./a.out 
static address: 60104c, value: 1
static address: 89e2c11c, value: 1

./a.out 
static address: 60104c, value: 1
static address: 226e03dc, value: 1

2 个答案:

答案 0 :(得分:1)

局部变量分配在被调用函数的堆栈帧上。堆栈帧通过堆栈指针(SP)寄存器引用,该寄存器在启动过程时由OS初始化。该程序使用SP动态分配堆栈空间并查找存储在那里的值。因此,这种类型的访问准备使用动态地址,并且知道操作系统可以选择初始化进程的堆栈帧,无论它在当前上下文中哪个最适合。

另一方面,“静态”变量通常由编译(汇编)代码中的常量地址引用。这就是为什么他们必须驻留在已知的编译时位置。

编辑:

正如有人指出的那样,SP的值会因程序执行而改变,具体取决于堆栈的使用情况。因此,如果从程序的不同部分调用相同的函数,则局部变量的地址每次甚至可能不同。

答案 1 :(得分:0)

首先,您定义的int staticvar = 0;称为global variable,而不是真正的静态变量。要定义静态变量,您必须在声明变量时添加static关键字,例如static int staticvar

现在,如果您看到C文件的汇编代码,您会注意到staticvar在编译时已被引用。这就是原因,你一直看到staticvar的内存位置相同。如果您还定义了全局/静态变量,则同样如此。

但是,局部变量获取运行时在stack中保留的内存,OS内核将控制该内存。这就是为什么你在每次运行时都会看到不同的内存位置。

即使您未在代码中添加sleep(),此行为仍然有效。

        .file   "test11.c"
        .local  staticvar
        .comm   staticvar,4,4
        .section        .rodata
        .align 8
.LC0:
        .string "static address: %x, value: %d\n"
.LC1:
        .string "local address: %x, value: %d\n"
        .text
.globl main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $32, %rsp
        movl    %edi, -20(%rbp)
        movq    %rsi, -32(%rbp)
        movl    $0, -4(%rbp)
        movl    staticvar(%rip), %eax
        addl    $1, %eax
        movl    %eax, staticvar(%rip)
        movl    -4(%rbp), %eax
        addl    $1, %eax
        movl    %eax, -4(%rbp)
        movl    $3, %edi
        movl    $0, %eax
        call    sleep
        movl    staticvar(%rip), %edx
        movl    $.LC0, %eax
        movl    $staticvar, %esi
        movq    %rax, %rdi
        movl    $0, %eax
        call    printf
        movl    -4(%rbp), %edx
        movl    $.LC1, %eax
        leaq    -4(%rbp), %rcx
        movq    %rcx, %rsi
        movq    %rax, %rdi
        movl    $0, %eax
        call    printf
        movl    $0, %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-11)"
        .section        .note.GNU-stack,"",@progbits