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

Same address for static variable but different for local variable

我正在努力学习操作系统。目前我在虚拟寻址。哪本书说如果我们有一个 static variable 和一个 local variable 并且我们更新它们并休眠一段时间并尝试打印它们的地址然后在多个这样的过程中 运行ning 一个将得到相同的内存地址。

这是因为每个进程都感觉自己拥有整个内存并且无法控制物理内存,因此地址将在多个进程之间保持相同 运行 同时。我理解这一点,但是当我 运行 我的程序时,我在静态变量之间获得相同的地址,但在局部变量之间获得不同的地址。凭借我对操作系统的了解,我无法理解为什么会这样。这是我的代码

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

局部变量分配在调用函数的栈帧上。堆栈帧通过堆栈指针 (SP) 寄存器引用,该寄存器在进程启动时由 OS 初始化。该程序使用 SP 动态分配堆栈 space 并查找存储在那里的值。所以这种类型的访问准备使用动态地址,并且知道 OS 可以选择在它认为最适合当前上下文的任何地方初始化进程的堆栈框架。

另一方面,

"Static" 变量通常由编译(汇编)代码中的常量地址引用。这就是为什么它们必须驻留在编译时已知的位置。

编辑:

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

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

现在,如果您查看 C 文件的汇编代码,您会注意到 staticvar 本身在编译时已被引用。这就是原因,您一直看到 staticvar 的相同内存位置。同样适用于,如果您还定义了 global/static 变量。

但是,局部变量在 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    , %rsp
        movl    %edi, -20(%rbp)
        movq    %rsi, -32(%rbp)
        movl    [=10=], -4(%rbp)
        movl    staticvar(%rip), %eax
        addl    , %eax
        movl    %eax, staticvar(%rip)
        movl    -4(%rbp), %eax
        addl    , %eax
        movl    %eax, -4(%rbp)
        movl    , %edi
        movl    [=10=], %eax
        call    sleep
        movl    staticvar(%rip), %edx
        movl    $.LC0, %eax
        movl    $staticvar, %esi
        movq    %rax, %rdi
        movl    [=10=], %eax
        call    printf
        movl    -4(%rbp), %edx
        movl    $.LC1, %eax
        leaq    -4(%rbp), %rcx
        movq    %rcx, %rsi
        movq    %rax, %rdi
        movl    [=10=], %eax
        call    printf
        movl    [=10=], %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