По сути, внутри функции локальные переменные хранятся в стековом фрейме.Внутри стекового фрейма порядок доступа к переменным может быть случайным.Я рекомендую прочитать это: http://www.cs.uwm.edu/classes/cs315/Bacon/Lecture/HTML/ch10s07.html
Рассмотрим следующий код
int main (void)
{
int a = 1, b = 2, c = 3;
c = c + 55;
a = a + 10;
return 0;
}
Компилятор может сгенерировать следующий код
main:
.LFB0:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
mov DWORD PTR [rbp-4], 1
mov DWORD PTR [rbp-8], 2
mov DWORD PTR [rbp-12], 3
add DWORD PTR [rbp-12], 55
add DWORD PTR [rbp-4], 10
mov eax, 0
pop rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
Обратите внимание, что переменная a
, b
и c
хранятся в ячейках rbp-4
, rbp-8
и rbp-12
, поэтому каждая переменная получает 4 байта (в моей системе).Это минус, потому что стек растет вниз, и начало кадра стека этой функции указывается содержимым rbp
.
Далее, обратите внимание, что сначала c = c + 55
, а затем a = a + 10
не толкаетили всплывающее окно, и просто получите доступ к местоположениям напрямую, используя add DWORD PTR [rbp-12], 55
и add DWORD PTR [rbp-4], 10
соответственно.Компилятор будет знать, где внутри стекового фрейма находятся эти переменные.
Обратите внимание на push rbp
до объявления и обращения к переменным.Эта операция сохранила текущее значение rbp
(базовый указатель, 64 бита) в кадре стека.Далее rbp
обновляется, чтобы получить новое значение, указывающее пределы для этой функции.Теперь в пределах этого ограничения все локальные переменные могут быть сохранены.Также обратите внимание на pop rbp
перед возвратом.Это восстанавливает старое значение rbp
из стекового кадра, которое было сохранено ранее, так что после ret
оно может вернуться к старому состоянию.