Почему каждый раз для локальной переменной выделяется один и тот же адрес?

0
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int main() {
    for(int i=0;i<5;++i)
    {
            int x=i;
         cout<<&x<<endl;
    }
}

теперь каждый раз он печатает один и тот же адрес памяти. Теперь x уничтожается после каждой итерации как единственной локальной переменной. Но почему тогда адрес x всегда один и тот же?

  • 4
    Почему бы не быть? Какое это имеет значение, если это (или нет)? Такие вещи оставлены на усмотрение компилятора и могут быть реализованы по-разному в разных системах в зависимости от этой архитектуры.
  • 2
    Подумайте, как используется стек.
Показать ещё 1 комментарий
Теги:
pointers

3 ответа

1
Лучший ответ

Мы можем посмотреть на разборку этой программы, чтобы понять, что происходит. Перед запуском мы можем немного упростить его, заменив cout, endl - >> printf. Нет ничего особенного, но разобранная петля будет немного короче.

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int main() {
    for(int i=0;i<5;++i)
    {
            int x=i;
            printf("%x\n",&x);
    }
}

Построить g++ -o main main.c, запустить ./main, дизассемблировать с objdump -d main, основной дизассемблировать с комментариями (значимые строки отмечены "<< -", удаляются машинные коды команд):

0000000000400810 <main>:
400810: push   %rbp       ; prologue
400811: mov    %rsp,%rbp  ; --------
400814: sub    $0x10,%rsp ; <<-- Prepare place at stack 
                                           ;      for two 4-byte variables!
                                           ; Addr. space: 0x4 + 0x4 = 0x10
400818: movl   $0x0,-0x4(%rbp)    ; init i with a 0
40081f: jmp    400841 <main+0x31> ; start loop -------------------.
400821: mov    -0x4(%rbp),%eax    ; <<-- move i to eax <----------|-.
400824: mov    %eax,-0x8(%rbp)    ; <<-- move eax to x            | |
400827: lea    -0x8(%rbp),%rax    ; <<-- load effective           | |
                                  ; address of x to rax           | |
40082b: mov    %rax,%rsi          ; param - address of x          | |
40082e: mov    $0x400940,%edi     ; param - address of format str | |
400833: mov    $0x0,%eax          ; param - final zero            | |
400838: callq  4006a0 <printf@plt>; call printf(..)               | |
40083d: addl   $0x1,-0x4(%rbp)    ; increment i                   | |
400841: cmpl   $0x4,-0x4(%rbp)    ; compare with 4     <----------' |     
400845: jle    400821 <main+0x11> ; if <= go to --------------------'
400847: mov    $0x0,%eax          ; default return value
40084c: jmp    400856 <main+0x46>
40084e: mov    %rax,%rdi
400851: callq  400710 <_Unwind_Resume@plt>
400856: leaveq 
400857: retq

Поэтому компилятор просто перемещает x за пределы цикла и удерживает его в стеке. Таким образом, мы имеем постоянный адрес x. Протестировано на x86_64 с помощью соглашения об использовании ABI с системой V AMD64.

0

Это может быть компилятор. Он разработан с оптимизационными функциями. Вы должны проверить код выхода компилятора, чтобы понять, почему это так.

0

Каждый x повторно использует то же пространство памяти, что и старый x, из предыдущей итерации, поскольку старый ему больше не нужен :)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню