Пробелы между переменными в стеке вызовов
Решил проверить хранение переменных в стеке вызовов.
#include <iostream>
int main()
{
volatile unsigned int a = 1;
volatile unsigned int b = 2;
volatile unsigned int c = 3;
volatile unsigned int* temp = &a;
while(true) std::cout << *(temp++) << std::endl;
}
Просто игнорируем тот факт, что данная программа выдаст ошибку из-за переименовывания адреса, не принадлежащий программе, это не имеет значения при постановке проблемы. Оказалось, что между переменными есть пробелы. Это имело бы смысл, если бы пробелы не хранили простой мусор. Возможно вопрос глупый, есть ли какая-то обоснованная причина существования этих пробелов?
Код работает только при конфигурациях Debug x32 (вместо инкремента нужно использовать декремент)/ x64. Длина пробелов так же зависит от выбранной конфигурации.
Ответы (2 шт):
Эта программа не работает. Предположение о том, что a, b, и c расположены в памяти друг за другом, и что память вообще можно просто так читать произвольно двигая указатель, неверное. А деже если они и были бы так расположены и их можно было бы так читать, то с обычным стеком, растущим вниз, вы бы читали мусор из пролога функции. Если программа и печатает какой-то мусор, то это просто проявление неопределенного поведения, и совсем не факт, что это действительно содержимое стека.
Если хотите инспектировать память - используйте просмотр памяти в отладчике.
Все очень зависит от компилятора и оптимизатора. Никакого требования хранить переменные так или иначе в стеке нет.
Давайте возьмем такой код, чтоб точно видеть, где находятся переменные, какие адреса у них etc
volatile unsigned int a = 1;
volatile unsigned int b = 2;
volatile unsigned int c = 3;
volatile unsigned int* temp = &a;
for(int i = 0; i < 20; ++i)
{
cout << (void*)&a << "-" << (void*)&b << "-" << (void*)&c << "-" << (void*)temp << " " << *temp << endl;
temp++;
}
gcc (https://ideone.com/Llv5xR) располагает их, как вы и хотели. VС++ 2017 x64 - с просветом, вероятно, выравнивая на 8 байт (включена оптимизация):
00000053420FF870-00000053420FF878-00000053420FF880-00000053420FF870 1
00000053420FF870-00000053420FF878-00000053420FF880-00000053420FF874 0
00000053420FF870-00000053420FF878-00000053420FF880-00000053420FF878 2
00000053420FF870-00000053420FF878-00000053420FF880-00000053420FF87C 0
00000053420FF870-00000053420FF878-00000053420FF880-00000053420FF880 3
00000053420FF870-00000053420FF878-00000053420FF880-00000053420FF884 0
Там же, но с выключенной оптимизацией -
000000846E5DF964-000000846E5DF970-000000846E5DF974-000000846E5DF964 1
000000846E5DF964-000000846E5DF970-000000846E5DF974-000000846E5DF968 1851652456
000000846E5DF964-000000846E5DF970-000000846E5DF974-000000846E5DF96C 132
000000846E5DF964-000000846E5DF970-000000846E5DF974-000000846E5DF970 2
000000846E5DF964-000000846E5DF970-000000846E5DF974-000000846E5DF974 3
000000846E5DF964-000000846E5DF970-000000846E5DF974-000000846E5DF978 3
000000846E5DF964-000000846E5DF970-000000846E5DF974-000000846E5DF97C 32759
000000846E5DF964-000000846E5DF970-000000846E5DF974-000000846E5DF980 2893161376
000000846E5DF964-000000846E5DF970-000000846E5DF974-000000846E5DF984 32759
000000846E5DF964-000000846E5DF970-000000846E5DF974-000000846E5DF988 2893161376
000000846E5DF964-000000846E5DF970-000000846E5DF974-000000846E5DF98C 32759
Оптимизация, но 32 разряда - кладет подряд:
010FF914-010FF918-010FF91C-010FF914 1
010FF914-010FF918-010FF91C-010FF918 2
010FF914-010FF918-010FF91C-010FF91C 3
010FF914-010FF918-010FF91C-010FF920 10122079
010FF914-010FF918-010FF91C-010FF924 1
010FF914-010FF918-010FF91C-010FF928 10592776
010FF914-010FF918-010FF91C-010FF92C 10612424
Кстати, если использовать ваш код, оптимизатор VC++ считает, что к b и c обращений вообще нет, и при оптимизации в каком-то режиме даже ухитряется слить их в одну переменную :)
Словом, это все - "depends on", так что вы в лучшем случае отвечаете на вопрос "как конкретно данный конкретный компилятор при данных конкретных опциях компилятора скомпилирует данный конкретный исходник"... :)
