Почему последовательно объявленные переменные-указатели хранятся в памяти в порядке убывания их адресов? - PullRequest
0 голосов
/ 17 сентября 2018

Я запустил следующий код и нашел что-то, чего я не понял:

main(){
char *s1 = "hi";
char *s2 = "Bye";
char *s3 = "Out";
printf("s %p | p %p : s %p | p %p : s %p | p %p", s1, &s1, s2, &s2, s3, &s3); 
}

Вывод этого выглядит так:

s 0000000000409020 | p 000000000064FE58 : s 0000000000409023 | p 000000000064FE50 : s 0000000000409027 | p 000000000064FE48

Здесь мы можем ясно видетьчто строки хранятся со своими начальными адресами в порядке возрастания значений, а адреса переменных-указателей находятся в порядке убывания значений - IN MEMORY.

Мне просто было интересно узнать, почему это так?Разве адреса переменных-указателей не должны быть в порядке возрастания?

Ответы [ 2 ]

0 голосов
/ 17 сентября 2018

Числовые значения адресов, хранящихся в s1, s2 и s3 (то есть адреса массивов символов, инициализированных в "hi", "Bye" и "Out"), гарантированно не равны, и они, вероятно, будут близки друг к другу, но не требуется, чтобы они были смежными или в каком-либо конкретном порядке. Аналогично, числовые значения адресов &s1, &s2 и &s3 (то есть адреса локальных переменных s1, s2 и s3) гарантированно не равны, и могут быть расположены близко друг к другу, но не обязательно должны быть смежными или в каком-либо определенном порядке.

s1, s2 и s3 содержат адреса строковых литералов. Строковые литералы являются синтаксическим сахаром для постоянных массивов со статической продолжительностью хранения, что означает, что все они выделяются и инициализируются до запуска вашей программы. Поскольку они не являются массивом того же со статической продолжительностью хранения, 1 они не могут иметь один и тот же адрес, но, кроме того, технически они могут находиться где угодно в ОЗУ. На практике они будут помещены в область ОЗУ, выделенную для данных только для чтения, что означает, что они будут находиться рядом друг с другом, но компилятор и компоновщик размещают эту область так, как им удобно, и вы не должны полагаться на то, как они это сделали.

&s1, &s2 и &s3 - адреса локальных переменных. Опять же, поскольку они не являются одной и той же переменной, они не могут иметь один и тот же адрес, и, опять же, они, вероятно, будут близки друг к другу, поскольку все они принадлежат одной и той же функции, но, опять же, точные отношения их адресов в памяти зависит от компилятора, и вы не должны полагаться на него. Люди, знакомые с языком ассемблера, часто думают, что локальные переменные будут помещаться в аппаратный стек по одной за раз, поэтому они должны быть последовательными в соответствии с «направлением роста стека» 2 , но скомпилированный код не не делай так. Компилятору удобнее перемещать указатель стека один раз при входе в каждую функцию, а затем оставлять его там, создавая объект, называемый "кадр стека". Это означает, что локальные переменные эффективно возникают сразу, и их адреса в пределах стекового фрейма могут быть самыми удобными для компилятора. (Например, они могут быть отсортированы по размеру, чтобы наименьшие переменные находились ближе всего к указателю стека и могли быть доступны с более короткими смещениями.)


1 В стандарте C есть особый случай, который позволяет "дедуплицировать" строки, т.е. если вы пишете const char *a = "foo"; в верхней части одной функции и const char *b = "foo"; в верхней части другой адреса, сохраненные в a и b, могут совпадать. Но ваши строки не идентичны, поэтому с ними нельзя обращаться.

2 Забавный факт: для реализации на C вообще не требуется аппаратный стек, не говоря уже о том, чтобы расти в определенном направлении! Требуется поддерживать рекурсивные вызовы функций, но как это сделать, совершенно не определено.

0 голосов
/ 17 сентября 2018

Строки хранятся в R/O - Data section вашей программы. Они могут храниться в любом порядке, который компилятор выберет .Локальные переменные хранятся в стеке, и хотя они также могут храниться в любом порядке, как правило, стек увеличивается в памяти, а куча - в памяти.

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