Даже без оптимизации упорядочение переменных в памяти обычно не то, на что вы можете рассчитывать.Порядок, с которым они сталкиваются, зависит от того, как вы на них смотрите.Если вы видели группу людей, стоящих в ряду, упорядоченных от самых коротких до самых высоких, другой человек может сказать, что на самом деле они упорядочены от самых высоких до самых коротких.
Первое, что влияет на порядок, в котором эти переменные находятся в памятиэто просто, как реализован компилятор.У него есть список вещей, и список может быть обработан от начала до конца или от конца до начала.Таким образом, компилятор читает ваш код, создает промежуточный код, и этот промежуточный код содержит список локальных переменных, которые необходимо поместить в стек.Компилятору на самом деле все равно, в каком порядке они находятся в коде, поэтому он просто смотрит на них в любом порядке, наиболее удобном.
Во-вторых, многие процессоры используют перевернутый стек.Если вы:
push A
push B
, тогда адрес A имеет больший адрес, чем B, даже если B находится на вершине стека (и на вершине A).Хороший способ представить это - использовать массив C:
int stk[BIG];
int stk_top = BIG;
, а затем
void stk_push(int x) {
stk_top--;
stk[stk_top] = x;
}
Как вы можете видеть, индекс stk_top действительно сжимается, так как стек получает больше элементов.
Теперь вернемся к оптимизации - компилятор довольно свободен, когда речь идет о переупорядочении вещей, которых нет в структурах.Это означает, что ваш компилятор может очень хорошо переупорядочить локальные переменные в стеке, а также добавить туда дополнительные байты заполнения для выравнивания.Кроме того, компилятор также свободен даже не помещать некоторые локальные переменные в стек.То, что вы называете локальную переменную, не означает, что компилятор должен действительно генерировать ее в программе.Если переменная фактически не используется, она может быть исключена из программы.Если переменная используется много, она может храниться в регистре.Если переменная используется только для части программы, то она может фактически существовать только временно, а используемая ею память может быть распределена между несколькими другими временными переменными во время выполнения функции.