Почему C не уменьшает указатель стека, если переменная выходит из области видимости? - PullRequest
5 голосов
/ 28 мая 2019
#include <stdio.h>
void main() {
    {
        int x;
        printf("%p\n", &x);
    }
    {
        int x;
        printf("%p\n", &x);
    }
}

Я бы подумал, запустив это, что он выведет одно и то же дважды.Когда он объявляет первую переменную, он увеличивает указатель стека, но затем покидает область видимости, поэтому уменьшает его, а затем просто повторяет процесс во второй раз, поэтому int x будет занимать одно и то же место в памяти в стеке оба раза.

Но это не так.Указатель стека не уменьшается, и int x в обоих случаях занимают разные места в стеке.На самом деле, первая int x все еще достижима, даже если ее охват исчез.

#include <stdio.h>
void main() {
    {
        int x = 10;
        printf("%p\n", &x);
    }
    {
        int x = 25;
        printf("%p\n", &x);
    }
    {
        int x = 71;
        printf("%p\n", &x);

        int *p = &x;
        printf("%i %i %i\n", *(p + 2), *(p + 1), *p);
    }
}

Почему это так?Что я недопонимаю?

Ответы [ 2 ]

6 голосов
/ 28 мая 2019

Стандарт C даже не упоминает стек.Компилятор может оптимизировать переменные, когда они не нужны.В стандарте C нет абсолютно ничего, что подразумевало бы, что распечатки не должны быть ни равны, ни не равны.

На моем компьютере это проявляется в том, что выдается различный вывод в зависимости от уровня оптимизации:

$ gcc c.c

/tmp$ ./a.out 
0x7ffd8733c3ac
0x7ffd8733c3a8

/tmp$ gcc c.c -O3

/tmp$ ./a.out 
0x7fff4e91544c
0x7fff4e91544c

Фактически, первое «int x» все еще доступно, даже если его область действия отсутствует.

Доступ к переменной, которая вышла из области действия, вызывает неопределенное поведение , что означает, что все может случиться.Это включает в себя случай, когда программа работает, как предполагалось.

Вот вывод из вашего второго фрагмента с различными оптимизациями:

/tmp$ ./a.out 
0x7ffd4df94864
0x7ffd4df94860
0x7ffd4df9485c
10 25 71

/tmp$ gcc c.c -O3

/tmp$ ./a.out 
0x7ffc30b4e44c
0x7ffc30b4e44c
0x7ffc30b4e44c
0 0 71

Когда вы получаете различное поведение в зависимости от уровня оптимизации, этопочти 100% признак того, что в вашей программе есть что-то, что вызывает неопределенное поведение.Существует очень и очень малая вероятность того, что вы столкнулись с ошибкой в ​​компиляторе.И кроме этих двух причин, я не могу думать ни о чем другом, что могло бы быть причиной.

4 голосов
/ 29 мая 2019

На практике, когда стек существует (как указывает ответ Бромана, стек не требуется, хотя равен требованием для поддержки рекурсии), компиляторы обычно генерируют кодон корректирует указатель стека только один раз при входе в функцию и еще раз при выходе из функции, даже если в функции есть под-области, ограничивающие время жизни отдельных переменных.

Это может показаться странным, если вы используетеписать на ассемблере вручную.Основная причина этого заключается в том, что каждая переменная, которая находится в стеке, имеет «слот стека» с фиксированным местоположением во всей функции, что дает компилятору максимальную гибкость при перемещении машинных инструкций дляоптимизация.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...