再次分配相同的内存空间

Abh*_*ogi 6 c unix linux gcc

在每次循环迭代中,一次又一次地声明变量j.那为什么它的地址保持不变

  • 不应该每次都给它一些随机地址吗?
  • 这个编译器是否依赖?
#include<stdio.h>
#include<malloc.h>

int main()
{
    int i=3;
    while (i--)
    {
        int j;
        printf("%p\n", &j);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

测试运行:-

shadyabhi@shadyabhi-desktop:~/c$ gcc test.c
shadyabhi@shadyabhi-desktop:~/c$ ./a.out
0x7fffc0b8e138
0x7fffc0b8e138
0x7fffc0b8e138
shadyabhi@shadyabhi-desktop:~/c$
Run Code Online (Sandbox Code Playgroud)

Mar*_*ins 12

它是堆栈中的内存.它不是从堆中分配的.堆栈在该循环中不会改变.

  • @Adam:每次都不是"真正"相同的变量,每次都在同一个位置(在这个实现中,几乎任何合理的C实现) (5认同)

小智 6

为什么会有所不同?编译器需要堆栈上的空间来存储int,并且每次它通过循环时都可以使用相同的空间.

顺便说一句,你根本就没有使用malloc过.j被保留在堆栈中.


And*_*lly 6

j永不改变地址的原因是因为编译器j在输入函数时为堆栈分配内存而不是j进入作用域时.

与往常一样,查看一些汇编代码可能有助于解释这个概念.采取以下功能: -

int foo(void)
   {
   int i=3;
   i++;
      {
      int j=2;
      i=j;
      }
   return i;
   }
Run Code Online (Sandbox Code Playgroud)

gcc将其转换为以下x86汇编代码: -

foo:
    pushl   %ebp                 ; save stack base pointer
    movl    %esp, %ebp           ; set base pointer to old top of stack
    subl    $8, %esp             ; allocate memory for local variables
    movl    $3, -4(%ebp)         ; initialize i
    leal    -4(%ebp), %eax       ; move address of i into eax
    incl    (%eax)               ; increment i by 1
    movl    $2, -8(%ebp)         ; initialize j
    movl    -8(%ebp), %eax       ; move j into accumulator
    movl    %eax, -4(%ebp)       ; set i to j
    movl    -4(%ebp), %eax       ; set the value of i as the function return value
    leave                        ; restore stack pointers
    ret                          ; return to caller
Run Code Online (Sandbox Code Playgroud)

让我们来看看这个汇编代码.第一行保存当前堆栈基指针,以便在函数退出时可以恢复,第二行将堆栈的当前顶部设置为此函数的新堆栈基指针.

第三行是为堆栈分配所有局部变量的内存.该指令subl $8, %esp从堆栈指针的当前顶部(esp寄存器)中减去8 .堆栈在内存中增长,因此这行代码实际上将堆栈上的内存增加了8个字节.我们在这个函数的两个整数,i并且j,每个需要4个字节,因此为什么它分配8个字节.

第4行i通过直接写入堆栈上的地址初始化为3.然后第5行和第6行加载并递增i.第7行j通过将值2写入j堆栈中分配的内存来初始化.请注意,当j进入第7行的范围时,汇编代码没有调整堆栈来为它分配内存,这已经在之前得到了解决.

我确信它很明显,但是编译器在函数开始时为所有局部变量分配内存的原因是因为这样做更有效.每次局部变量进入或超出范围时调整堆栈将导致对堆栈指针进行大量不必要的操作而无法获得增益.

我相信你可以弄清楚其余的汇编代码自己做了什么,如果不发表评论,我会引导你完成它.