Стеки обычно растут вниз. Для этого нет существенной причины; это в основном просто результат исторического развития. Область стека выделяется для стека, указатель стека устанавливается так, чтобы он указывал на его верхнюю часть, и запускается основная процедура программы. Поскольку программе требуется больше места в стеке, она уменьшает указатель стека.
В вашем примере происходит то, что компилятор назначает пространство для объектов в том порядке, в котором он их встречает. dx
отображается первым, поэтому ему присваивается следующее доступное пространство в стеке 0x28ff13
. Затем видно ca
и ему присваивается 0x28ff12
. Мы видим, что по мере роста стека он переходит от более высоких адресов (с которых он начинался) к более низким адресам.
Когда компилятор получает значение cz
, для которого вы запросили восьмибайтовое выравнивание, компилятор переходит к следующему кратному восьми (все еще в направлении вниз), которое равно 0x28ff08
.
Конечно, компилятор мог бы взглянуть на всю ситуацию (вместо того, чтобы смотреть на каждый объект по одному) и поместить cz
в 0x28ff10
и поместить вокруг него другие объекты, используя меньше места в стеке. Если вы компилируете с включенной оптимизацией, это может сделать компилятор. С другой стороны, компилятор может требовать от вашей платформы, чтобы указатель стека был выровнен до восьми байтов (или более), поэтому перестановка этих конкретных объектов в любом случае не сэкономила бы пространство стека.
В стандарте C нет никаких правил по этому поводу. Компилятор может свободно размещать свой стек по своему выбору.