Когда будет перераспределена память стека?

существует следующий код:

int fun(){

    char* pc = NULL;

    {
        char ac[100] = "addjfidsfsfds";
        pc = ac;
    }

    ...

    pc[0] = 'd';
    printf("%sn", pc);
    ...
}

итак, могу ли я использовать pc безопасно после ac заканчивается? Потому что я не уверен, выделена ли память стека для ac будет перераспределен компилятором для другого использования или нет.

4 ответов


дефект в понимании, который вы имеете, имеет отношение к длительность хранения объектов. Если вы не работаете с потоками, у вас есть три типа, с которыми нужно иметь дело,статический, автоматический и выделенный. Путем объявления char ac[100] = "addjfidsfsfds"; внутри блока и без static спецификатор класса хранения, длительность хранения автоматическая и его срок службы заканчивается, когда заканчивается выполнение bock. Пытаясь затем открыть значение неопределено Поведение.

стандарт C подробно излагает это в разделе 6.2.4, например

C11 - 6.2.4 продолжительность хранения объекты

1 объект имеет длительность хранения, определяющую его время жизни. Там есть четыре продолжительности хранения:статический, поток, автоматический, и выделено. Выделенное хранилище описано в 7.22.3.

2 продолжительность жизни объекта часть выполнения программы во время которого хранение гарантированно будет зарезервировано для него. объект существует, имеет постоянный адрес, 33) и сохраняет свое последнее сохраненное значение на протяжении всей своей жизни.34) Если объект упоминается вне его жизнь,поведение не определено. Значение указателя становится неопределенным, когда объект, на который он указывает (или просто мимо) достигает конца своей жизни.

3 объект, идентификатор которого объявлен без класса хранения спецификатор _Thread_local, и либо с внешней или внутренней связью или с помощью спецификатора класса хранения static, имеет статическое хранение продолжительность. Его продолжительность жизни - это все выполнение программы и его сохраненное значение инициализируется только один раз, до запуска программы.

( опущено _Thread_local детали)

5 объект, идентификатор которого объявлен без привязки и без спецификатор класса хранения static имеет автоматическая длительность хранения, как сделайте несколько составных литералов. Результат попытки косвенно доступ к объекту с автоматической длительностью хранения из потока other чем тот, с которым связан объект реализация-определено.

6 для такого объекта, который не имеет массива переменной длины типа, ее срок службы простирается от входа в блок, с которым он связанный до тех пор, пока выполнение этого блока не закончится каким-либо образом. (Входящий закрытый блок или вызов функции приостанавливается, но не заканчивается, выполнение текущего блока.) Если блок введен рекурсивно, каждый раз создается новый экземпляр объекта. Начальное значение объект неопределен. Если инициализация указана для объект, он выполняется каждый раз, когда объявление или соединение литерал достигается при выполнении блока; в противном случае значение становится неопределенным каждый раз, когда достигается декларация.

7 для такого объекта, который имеет тип массива переменной длины, его срок службы простирается от объявления объекта до выполнение программы выходит за рамки декларации.35) если области вводится рекурсивно, новый экземпляр объекта создается каждый раз. Начальное значение объекта не определено.

Если когда-либо возникал вопрос о том, разрешен ли доступ к значению или нет, обратитесь к норматив.


Из Стандарта C#6.2.1p4 [выделено мной]

каждый другой идентификатор имеет область, определяемую размещением его объявления (в деклараторе или спецификаторе типа). Если Декларатор или спецификатор типа, объявляющий идентификатор, появляется вне любого блока или списка параметров, идентификатор имеет область файла, которая завершается в конце единицы перевода. если появляется Декларатор или спецификатор типа, объявляющий идентификатор внутри блока или в списке объявлений параметров в определении функции, идентификатор имеет область действия блока, который заканчивается в конце блока. ......

переменная ac - локальная (автоматическая) нестатическая переменная, срок службы которой ограничен областью действия, т. е. блоком, в котором она была объявлена. Любая попытка получить к нему доступ за пределами его жизни приводит к неопределенному поведению.

Из Стандарта C#6.2.4p2 [акцент мой]

время жизни объекта-это часть выполнения программы, в течение которой для него гарантированно зарезервировано хранилище. Объект существует, имеет постоянный адрес,33) и сохраняет свое последнее сохраненное значение в течение всего срока службы.34) если объект упоминается за пределами его жизни, поведение неопределено. Значение указателя становится неопределенным, когда объект, на который он указывает (или только что прошел), достигает конца своего срока службы.


используя pc вне внутренней области небезопасно в вашем примере. Потому что ac уничтожается сразу после pc = ac, у вас есть классический оборванных указатель. Если включено достаточное количество предупреждений, я предполагаю, что большинство компиляторов будут выдавать предупреждения.

этой мая работает на вашей системе, но это не значит, что это безопасно. Некоторые компиляторы могут выбрать восстановление всех примитивов сразу в качестве оптимизации, но они не обязаны это делать.


Это мая перераспределяется после окончания блока (когда он выходит за рамки).

ли будет перераспределение варьируется в зависимости от программы и архитектуры машины, на которой она работает (и компилятора).

Это скорее для перераспределения при объявлении другой локальной переменной (в стеке); и / или при вызове функции (которая толкает значения параметров и обратный адрес на стек, и позволяет вызываемой функции объявлять новые переменные).

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