Пробелы между переменными в стеке вызовов

Решил проверить хранение переменных в стеке вызовов.

#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 шт):

Автор решения: user7860670

Эта программа не работает. Предположение о том, что a, b, и c расположены в памяти друг за другом, и что память вообще можно просто так читать произвольно двигая указатель, неверное. А деже если они и были бы так расположены и их можно было бы так читать, то с обычным стеком, растущим вниз, вы бы читали мусор из пролога функции. Если программа и печатает какой-то мусор, то это просто проявление неопределенного поведения, и совсем не факт, что это действительно содержимое стека.

Если хотите инспектировать память - используйте просмотр памяти в отладчике.

→ Ссылка
Автор решения: Harry

Все очень зависит от компилятора и оптимизатора. Никакого требования хранить переменные так или иначе в стеке нет.

Давайте возьмем такой код, чтоб точно видеть, где находятся переменные, какие адреса у них 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", так что вы в лучшем случае отвечаете на вопрос "как конкретно данный конкретный компилятор при данных конкретных опциях компилятора скомпилирует данный конкретный исходник"... :)

→ Ссылка