Статическое размещение данных

Размещение программ и данных в памяти

Компилятор языка программирования генерируют код, который во время выполнения хранится в оперативной памяти так же, как и обрабатываемые данные. Программа после загрузки в оперативную память имеет следующую структуру:

Исполняемый модуль  
 
=
Сегмент кода
  исполняемый машинный код
+
Сегмент данных
статические данные (extern и static) объем этого сегмента ограничен (64кБ, 32кБ)
+
Сегмент стека
результаты промежуточных вычислений; временные переменные; локальные переменные;
        +    
   
Динамически распределяемая память  
 

Статическое размещение данных в памяти (в сегменте данных или сегменте стека) осуществляется по формуле:

Определение Объявление = инициализация;

int i=1; // тип идентификатор=значение

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

  • глобальное, когда в любой момент во время работы с переменной всегда ассоциирована область памяти и обратиться к ней можно из любой точки программы;
  • статическое, когда во время работы с переменной ассоциирована область памяти, но обратиться к ней можно только из определенных точек программы;
  • локальное, когда при каждом входе в блок операторов { } для хранения переменной выделяется область памяти, а при выходе память освобождается и переменная теряет свое значение.

Для управления статическим размещением переменных в памяти, их временем жизни и областью видимости язык программирования C++ предоставляет понятие классов памяти и рад ключевых слов модификаторов типа:

  1. extern используется для определения глобальных переменных. Память для переменных extern распределяется постоянно. Такая переменная глобальна для всех функций и доступна в любой точке программы. Значение переменной всегда сохраняется.
  2. static используется для определения статических переменных. Статические определения используются в случае если необходимо сохранять предыдущее значение при повторном входе в блок операторов { }.
  3. auto используются для определения автоматических переменных. Переменные определенные внутри функции или блока операторов { } по умолчанию являются автоматическими. При входе в блок { } программа автоматически располагает переменную в сегменте стека. При выходе из блока память освобождается, а значения теряются.
  4. register используются для определения регистровых переменных. Переменные с классом памяти register, ассоциируются со скоростными регистрами памяти процессора. Но это не всегда возможно, поэтому часто компилятор преобразует такие переменные к классу auto.

Переменные extern и static явно не инициализированные программистом устанавливаются системой в нуль. Переменные auto и register не инициализируются и могут содержать "мусор".

Указатели и ссылки

На хранение адреса в современных вычислительных системах отводится 32 бита (4 байта) или 64 бита (8 байт). Это значит, что теоретически программы могут управлять памятью объемом около 4096 Мб (а для 64-разрядных систем - около 16777215 Тб). Для работы с памятью каждая из её ячеек нумеруется.

Пусть для хранения переменной i типа int отводится 4 байта. Тогда структура хранения этой переменной в оперативной памяти может иметь следующий вид:

Адрес ячейки памяти Содержимое ячейки памяти
...... .........
0x0012FF70  
0x0012FF71  
0x0012FF72  
0x0012FF73  
0x0012FF74 .........
....... ..........

Указатель (pointer) - это переменная (особого вида), предназначенная для хранения адреса объекта (адреса ячейки памяти, в которых хранится значение переменной). Диапазон значений для любого указателя включает специальный адрес 0 (null) и диапазон положительных целых чисел, который интерпретируется как машинные адреса.

Рассмотрим пример работы с указателем:

int *p; // переменная типа указателя
int i=2;
p=&i; // после выполнения p=0x0012FF70

Для получения адреса ячейки памяти, в которой хранится переменная, и последующей инициализации переменной типа указатель использовалась операция получения адреса (&). Таким образом, значение переменной p представляет собой адрес ячейки (указатель на то место в памяти), в которой хранится значение переменной i.

Язык программирования предоставляет нам возможность применять к указателям арифметические операции:

int j;
j=*p; // операция получения значения по указателю (* или разыменование)
int t=*p+1; // t будет равно 3

p++; // что будет?

Для получения значения переменной хранящейся в ячейке, на которую указывает указатель использовался оператор разыменования (*).

Ссылка (referenсe) - это переменная (особого вида), которая представляет собой альтернативное имя (псевдоним, alias) другой переменной.

int i=1;
int& r=i; // r - новое альтернативное имя для переменной i. r и i размещены (ссылаются) на одно и то же место в памяти
int x=r; // x=1
r=2; // i=2 тоже
r++; // чему равно значение перемнных r и i?

Особенность ссылок заключается в том, что ссылку нельзя объявить без инициализации, она сразу должна на что-то ссылаться, то есть быть псевдонимом для какого-то объекта. Псевдонима для "ничто" не может существовать.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: