Уважаемые коллеги! Мне хочется понять как работает стек, на примере функции из трёх переменных. void f2() { int B = 5 int *pB = &B // задание адреса в указатель int &sB = B //задание объекта в ссылку cout << "addres of B = " << &B << "<br>" cout << "value of B = " << B << "<br>" cout << "addres of pB = " << &pB << "<br>" cout << "value of pB = " << pB << "<br>" cout << "addres of sB = " << &sB << "<br>" cout << "value of sB = " << sB << "<br>" } int main() { f2() system("PAUSE") return 0 } Output: addres of B = 0038F644 value of B = 5 addres of pB = 0038F638 value of pB = 0038F644 addres of sB = 0038F644 value of sB = 5 1. Непонятка между первой и третьей строкой. В адресном пространстве, как я полагал, адрес более новой переменной должен быть больше старой. На деле: `0038F638 - 0038F644 = -C ` То есть сдвиг на 12 позиций назад. Хотя один из программеров с большим опытом, говорил, что сдвиг пойдёт на 4 позиции вперёд - на размерность int, который выражен в байтах. 2. Адрес sB - вообще совпал с адресом B! А значение sB - совпал сo значением B! Мне казалось очевидным, что значение помещенное в sB должно быть равным адресу B. А адрес sB должен быть сдвинут на четыре позиции (sizeof(int)) вперёд, относительно адреса предыдущей переменной. Вопросы: Чем можно объяснить наблюдаемое поведение? Каким образом (на самом деле) происходит присвоение адреса следующей переменной, относительно предыдущей? Есть ли возможность распечатать стек более грамотным способом, чем это я сделал? (Я хочу видеть стек в виде трой записей - тип - значение - адрес).
Ответ В адресном пространстве, как я полагал, адрес более новой переменной должен быть больше старой. В большинстве "традиционных" платформ стек растет сверху-вниз: от старших адресов к младшим. Поэтому даже если бы компилятор размещал ваши переменные "по порядку", то не было бы ничего удивительного в том, что адрес более "новой" переменной меньше адреса более "старой". Но на самом деле никакого порядка в размещении отдельных переменных нет и ваши сравнения адресов - бессмысленны. В традиционной реализации память для всех локальных переменных функции выделяется сразу, одним "кадром стека" в начале работы функции. Внутри этого кадра стека компилятор еще на стадии компиляции разработает некую фиксированную карту расположения локальных переменных. При этом он может (и будет) располагать локальные переменные в этой карте совершенно произвольным образом, руководствуясь оптимизационными соображениями выравнивания, экономии памяти и т.д. и т.п. Поэтому ваш порядок объявления переменных не значит вообще ничего и разность адресов двух "соседних" переменных может быть какой угодно как по величине так и по знаку. Адрес sB - вообще совпал с адресом B! Какой еще "адрес sB"? sB - ссылка. Ссылочный тип не является объектным, концептуально памяти не занимает и адреса не имеет. Никакого "адреса sB" в языке С++ нет и быть не может. После объявления int &sB = B выражение &sB будет давать именно адрес B, что вы и наблюдаете. Нет ничего удивительного в том, что адрес B совпадает с адресом B. Каким образом (на самом деле) происходит присвоение адреса следующей переменной, относительно предыдущей? Никаким конкретно. Как компилятору захочется в данном конкретном случае - так и будет. Эти решения принимаются компилятором на основе логики, которая на уровне языка не видна. Какой-то порядок в языке С++ существует (может существовать) только между элементами одного массива или полями одного класса. Есть ли возможность распечатать стек более грамотным способом, чем это я сделал? (Я хочу видеть стек в виде трой записей - тип - значение - адрес). На уровне языка - разумеется, нет. А дальше можете поизучать формат отладочной информации, генерируемой вашим компилятором, и те API, которые ваша реализация предоставляет (если предоставляет) для доступа к этой отладочной информации. Там все это будет.